OSDN Git Service

2000-07-21 Alexandre Petit-Bianco <apbianco@cygnus.com>
[pf3gnuchains/gcc-fork.git] / gcc / tree.c
index d259420..e2ffc4b 100644 (file)
@@ -1,5 +1,6 @@
 /* Language-independent node constructors for parse phase of GNU compiler.
-   Copyright (C) 1987, 88, 92-98, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -37,15 +38,20 @@ Boston, MA 02111-1307, USA.  */
 #include "system.h"
 #include "flags.h"
 #include "tree.h"
-#include "except.h"
+#include "tm_p.h"
 #include "function.h"
 #include "obstack.h"
 #include "toplev.h"
+#include "ggc.h"
+#include "hashtab.h"
+#include "output.h"
 
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 /* obstack.[ch] explicitly declined to prototype this. */
-extern int _obstack_allocated_p PROTO ((struct obstack *h, GENERIC_PTR obj));
+extern int _obstack_allocated_p PARAMS ((struct obstack *h, PTR obj));
+
+static void unsave_expr_now_r PARAMS ((tree));
 
 /* Tree nodes of permanent duration are allocated in this obstack.
    They are the identifier nodes, and everything outside of
@@ -65,21 +71,6 @@ struct obstack *function_maybepermanent_obstack;
 
 struct obstack maybepermanent_obstack;
 
-/* This is a list of function_maybepermanent_obstacks for top-level inline
-   functions that are compiled in the middle of compiling other functions.  */
-
-struct simple_obstack_stack *toplev_inline_obstacks;
-
-/* Former elements of toplev_inline_obstacks that have been recycled.  */
-
-struct simple_obstack_stack *extra_inline_obstacks;
-
-/* This is a list of function_maybepermanent_obstacks for inline functions
-   nested in the current function that were compiled in the middle of
-   compiling other functions.  */
-
-struct simple_obstack_stack *inline_obstacks;
-
 /* The contents of the current function definition are allocated
    in this obstack, and all are freed at the end of the function.
    For top-level functions, this is temporary_obstack.
@@ -194,7 +185,7 @@ int tree_code_length[MAX_TREE_CODES] = {
    Used for printing out the tree and error messages.  */
 #define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
 
-char *tree_code_name[MAX_TREE_CODES] = {
+const char *tree_code_name[MAX_TREE_CODES] = {
 #include "tree.def"
 };
 #undef DEFTREECODE
@@ -224,7 +215,7 @@ int tree_node_counts[(int)all_kinds];
 int tree_node_sizes[(int)all_kinds];
 int id_string_size = 0;
 
-const char *tree_node_kind_names[] = {
+static const char * const tree_node_kind_names[] = {
   "decls",
   "types",
   "blocks",
@@ -255,21 +246,58 @@ static int next_decl_uid;
 /* Unique id for next type created.  */
 static int next_type_uid = 1;
 
-/* The language-specific function for alias analysis.  If NULL, the
-   language does not do any special alias analysis.  */
-int (*lang_get_alias_set) PROTO((tree));
-
 /* Here is how primitive or already-canonicalized types' hash
    codes are made.  */
 #define TYPE_HASH(TYPE) ((unsigned long) (TYPE) & 0777777)
 
-static void set_type_quals PROTO((tree, int));
-static void append_random_chars PROTO((char *));
-static void build_real_from_int_cst_1 PROTO((PTR));
+/* Since we cannot rehash a type after it is in the table, we have to
+   keep the hash code.  */
 
-extern char *mode_name[];
+struct type_hash
+{
+  unsigned long hash;
+  tree type;
+};
 
-void gcc_obstack_init ();
+/* Initial size of the hash table (rounded to next prime). */
+#define TYPE_HASH_INITIAL_SIZE 1000
+
+/* Now here is the hash table.  When recording a type, it is added to
+   the slot whose index is the hash code.  Note that the hash table is
+   used for several kinds of types (function types, array types and
+   array index range types, for now).  While all these live in the
+   same table, they are completely independent, and the hash code is
+   computed differently for each of these.  */
+
+htab_t type_hash_table;
+
+static void build_real_from_int_cst_1 PARAMS ((PTR));
+static void set_type_quals PARAMS ((tree, int));
+static void append_random_chars PARAMS ((char *));
+static void mark_type_hash PARAMS ((void *));
+static int type_hash_eq PARAMS ((const void*, const void*));
+static unsigned int type_hash_hash PARAMS ((const void*));
+static void print_type_hash_statistics PARAMS((void));
+static int mark_hash_entry PARAMS((void **, void *));
+static void finish_vector_type PARAMS((tree));
+
+/* If non-null, these are language-specific helper functions for
+   unsave_expr_now.  If present, LANG_UNSAVE is called before its
+   argument (an UNSAVE_EXPR) is to be unsaved, and all other
+   processing in unsave_expr_now is aborted.  LANG_UNSAVE_EXPR_NOW is
+   called from unsave_expr_1 for language-specific tree codes.  */
+void (*lang_unsave) PARAMS ((tree *));
+void (*lang_unsave_expr_now) PARAMS ((tree));
+
+/* The string used as a placeholder instead of a source file name for
+   built-in tree nodes.  The variable, which is dynamically allocated,
+   should be used; the macro is only used to initialize it.  */
+
+static char *built_in_filename;
+#define BUILT_IN_FILENAME ("<built-in>")
+\f
+tree global_trees[TI_MAX];
+tree integer_types[itk_none];
 \f
 /* Init the principal obstacks.  */
 
@@ -298,6 +326,14 @@ init_obstacks ()
 
   /* Init the hash table of identifiers.  */
   bzero ((char *) hash_table, sizeof hash_table);
+  ggc_add_tree_root (hash_table, sizeof hash_table / sizeof (tree));
+
+  /* Initialize the hash table of types.  */
+  type_hash_table = htab_create (TYPE_HASH_INITIAL_SIZE, type_hash_hash, 
+                                type_hash_eq, 0);
+  ggc_add_root (&type_hash_table, 1, sizeof type_hash_table, mark_type_hash);
+  ggc_add_tree_root (global_trees, TI_MAX);
+  ggc_add_tree_root (integer_types, itk_none);
 }
 
 void
@@ -316,8 +352,8 @@ gcc_obstack_init (obstack)
 #define OBSTACK_CHUNK_FREE free
 #endif
   _obstack_begin (obstack, OBSTACK_CHUNK_SIZE, 0,
-                 (void *(*) ()) OBSTACK_CHUNK_ALLOC,
-                 (void (*) ()) OBSTACK_CHUNK_FREE);
+                 (void *(*) PARAMS ((long))) OBSTACK_CHUNK_ALLOC,
+                 (void (*) PARAMS ((void *))) OBSTACK_CHUNK_FREE);
 }
 
 /* Save all variables describing the current status into the structure
@@ -330,9 +366,8 @@ gcc_obstack_init (obstack)
    compile; if it isn't current_function_decl, we have to play some games.  */
 
 void
-save_tree_status (p, context)
+save_tree_status (p)
      struct function *p;
-     tree context;
 {
   p->all_types_permanent = all_types_permanent;
   p->momentary_stack = momentary_stack;
@@ -346,50 +381,10 @@ save_tree_status (p, context)
   p->expression_obstack = expression_obstack;
   p->saveable_obstack = saveable_obstack;
   p->rtl_obstack = rtl_obstack;
-  p->inline_obstacks = inline_obstacks;
-
-  if (current_function_decl && context == current_function_decl)
-    /* Objects that need to be saved in this function can be in the nonsaved
-       obstack of the enclosing function since they can't possibly be needed
-       once it has returned.  */
-    function_maybepermanent_obstack = function_obstack;
-  else
-    {
-      /* We're compiling a function which isn't nested in the current
-         function.  We need to create a new maybepermanent_obstack for this
-         function, since it can't go onto any of the existing obstacks.  */
-      struct simple_obstack_stack **head;
-      struct simple_obstack_stack *current;
-
-      if (context == NULL_TREE)
-       head = &toplev_inline_obstacks;
-      else
-       {
-         struct function *f = find_function_data (context);
-         head = &f->inline_obstacks;
-       }
-
-      if (context == NULL_TREE && extra_inline_obstacks)
-       {
-         current = extra_inline_obstacks;
-         extra_inline_obstacks = current->next;
-       }
-      else
-       {
-         current = ((struct simple_obstack_stack *)
-                    xmalloc (sizeof (struct simple_obstack_stack)));
-
-         current->obstack
-           = (struct obstack *) xmalloc (sizeof (struct obstack));
-         gcc_obstack_init (current->obstack);
-       }
-
-      function_maybepermanent_obstack = current->obstack;
-
-      current->next = *head;
-      *head = current;
-    }      
 
+  function_maybepermanent_obstack
+    = (struct obstack *) xmalloc (sizeof (struct obstack));
+  gcc_obstack_init (function_maybepermanent_obstack);
   maybepermanent_firstobj
     = (char *) obstack_finish (function_maybepermanent_obstack);
 
@@ -409,9 +404,8 @@ save_tree_status (p, context)
    This is used after a nested function.  */
 
 void
-restore_tree_status (p, context)
+restore_tree_status (p)
      struct function *p;
-     tree context;
 {
   all_types_permanent = p->all_types_permanent;
   momentary_stack = p->momentary_stack;
@@ -419,41 +413,18 @@ restore_tree_status (p, context)
   obstack_free (&momentary_obstack, momentary_function_firstobj);
 
   /* Free saveable storage used by the function just compiled and not
-     saved.
-
-     CAUTION: This is in function_obstack of the containing function.
-     So we must be sure that we never allocate from that obstack during
-     the compilation of a nested function if we expect it to survive
-     past the nested function's end.  */
+     saved.  */
   obstack_free (function_maybepermanent_obstack, maybepermanent_firstobj);
-
-  /* If we were compiling a toplevel function, we can free this space now.  */
-  if (context == NULL_TREE)
+  if (obstack_empty_p (function_maybepermanent_obstack))
     {
-      obstack_free (&temporary_obstack, temporary_firstobj);
-      obstack_free (&momentary_obstack, momentary_function_firstobj);
+      obstack_free (function_maybepermanent_obstack, NULL);
+      free (function_maybepermanent_obstack);
     }
 
-  /* If we were compiling a toplevel function that we don't actually want
-     to save anything from, return the obstack to the pool.  */
-  if (context == NULL_TREE
-      && obstack_empty_p (function_maybepermanent_obstack))
-    {
-      struct simple_obstack_stack *current, **p = &toplev_inline_obstacks;
-
-      if ((*p) != NULL)
-       {
-         while ((*p)->obstack != function_maybepermanent_obstack)
-           p = &((*p)->next);
-         current = *p;
-         *p = current->next;
-
-         current->next = extra_inline_obstacks;
-         extra_inline_obstacks = current;
-       }
-    }
+  obstack_free (&temporary_obstack, temporary_firstobj);
+  obstack_free (&momentary_obstack, momentary_function_firstobj);
 
-  obstack_free (function_obstack, 0);
+  obstack_free (function_obstack, NULL);
   free (function_obstack);
 
   temporary_firstobj = p->temporary_firstobj;
@@ -466,7 +437,6 @@ restore_tree_status (p, context)
   expression_obstack = p->expression_obstack;
   saveable_obstack = p->saveable_obstack;
   rtl_obstack = p->rtl_obstack;
-  inline_obstacks = p->inline_obstacks;
 }
 \f
 /* Start allocating on the temporary (per function) obstack.
@@ -483,7 +453,6 @@ temporary_allocation ()
   expression_obstack = function_obstack;
   rtl_obstack = saveable_obstack = function_maybepermanent_obstack;
   momentary_stack = 0;
-  inline_obstacks = 0;
 }
 
 /* Start allocating on the permanent obstack but don't
@@ -530,8 +499,9 @@ void
 push_obstacks (current, saveable)
      struct obstack *current, *saveable;
 {
-  struct obstack_stack *p
-    = (struct obstack_stack *) obstack_alloc (&obstack_stack_obstack,
+  struct obstack_stack *p;
+
+  p = (struct obstack_stack *) obstack_alloc (&obstack_stack_obstack,
                                              (sizeof (struct obstack_stack)));
 
   p->current = current_obstack;
@@ -551,8 +521,9 @@ push_obstacks (current, saveable)
 void
 push_obstacks_nochange ()
 {
-  struct obstack_stack *p
-    = (struct obstack_stack *) obstack_alloc (&obstack_stack_obstack,
+  struct obstack_stack *p;
+  
+  p = (struct obstack_stack *) obstack_alloc (&obstack_stack_obstack,
                                              (sizeof (struct obstack_stack)));
 
   p->current = current_obstack;
@@ -568,7 +539,9 @@ push_obstacks_nochange ()
 void
 pop_obstacks ()
 {
-  struct obstack_stack *p = obstack_stack;
+  struct obstack_stack *p;
+
+  p = obstack_stack;
   obstack_stack = p->next;
 
   current_obstack = p->current;
@@ -608,20 +581,10 @@ permanent_allocation (function_end)
     }
   else
     obstack_free (&momentary_obstack, momentary_firstobj);
+
   obstack_free (function_maybepermanent_obstack, maybepermanent_firstobj);
   obstack_free (&temp_decl_obstack, temp_decl_firstobj);
 
-  /* Free up the maybepermanent_obstacks for any of our nested functions
-     which were compiled at a lower level.  */
-  while (inline_obstacks)
-    {
-      struct simple_obstack_stack *current = inline_obstacks;
-      inline_obstacks = current->next;
-      obstack_free (current->obstack, 0);
-      free (current->obstack);
-      free (current);
-    }
-
   current_obstack = &permanent_obstack;
   expression_obstack = &permanent_obstack;
   rtl_obstack = saveable_obstack = &permanent_obstack;
@@ -925,11 +888,15 @@ resume_momentary (yes)
 void
 init_tree_codes ()
 {
-  
+  built_in_filename
+    = ggc_alloc_string (BUILT_IN_FILENAME, sizeof (BUILT_IN_FILENAME));
+  ggc_add_string_root (&built_in_filename, 1);
 }
 
 /* Return a newly allocated node of code CODE.
    Initialize the node's unique id and its TREE_PERMANENT flag.
+   Note that if garbage collection is in use, TREE_PERMANENT will
+   always be zero - we want to eliminate use of TREE_PERMANENT.
    For decl and type nodes, some other fields are initialized.
    The rest of the node is initialized to zero.
 
@@ -1026,7 +993,7 @@ make_node (code)
       if (code == BIND_EXPR && obstack != &permanent_obstack)
        obstack = saveable_obstack;
       length = sizeof (struct tree_exp)
-       + (tree_code_length[(int) code] - 1) * sizeof (char *);
+       + (TREE_CODE_LENGTH (code) - 1) * sizeof (char *);
       break;
 
     case 'c':  /* a constant */
@@ -1035,7 +1002,7 @@ make_node (code)
 #endif
       obstack = expression_obstack;
 
-      /* We can't use tree_code_length for INTEGER_CST, since the number of
+      /* We can't use TREE_CODE_LENGTH for INTEGER_CST, since the number of
         words is machine-dependent due to varying length of HOST_WIDE_INT,
         which might be wider than a pointer (e.g., long long).  Similarly
         for REAL_CST, since the number of words is machine-dependent due
@@ -1047,7 +1014,7 @@ make_node (code)
        length = sizeof (struct tree_real_cst);
       else
        length = sizeof (struct tree_common)
-         + tree_code_length[(int) code] * sizeof (char *);
+         + TREE_CODE_LENGTH (code) * sizeof (char *);
       break;
 
     case 'x':  /* something random, like an identifier.  */
@@ -1062,7 +1029,7 @@ make_node (code)
        kind = x_kind;
 #endif
       length = sizeof (struct tree_common)
-       + tree_code_length[(int) code] * sizeof (char *);
+       + TREE_CODE_LENGTH (code) * sizeof (char *);
       /* Identifier nodes are always permanent since they are
         unique in a compiler run.  */
       if (code == IDENTIFIER_NODE) obstack = &permanent_obstack;
@@ -1072,8 +1039,12 @@ make_node (code)
       abort ();
     }
 
-  t = (tree) obstack_alloc (obstack, length);
-  bzero ((PTR) t, length);
+  if (ggc_p)
+    t = ggc_alloc_tree (length);
+  else
+    t = (tree) obstack_alloc (obstack, length);
+
+  memset ((PTR) t, 0, length);
 
 #ifdef GATHER_STATISTICS
   tree_node_counts[(int)kind]++;
@@ -1081,8 +1052,7 @@ make_node (code)
 #endif
 
   TREE_SET_CODE (t, code);
-  if (obstack == &permanent_obstack)
-    TREE_PERMANENT (t) = 1;
+  TREE_SET_PERMANENT (t);
 
   switch (type)
     {
@@ -1094,10 +1064,11 @@ make_node (code)
     case 'd':
       if (code != FUNCTION_DECL)
        DECL_ALIGN (t) = 1;
-      DECL_IN_SYSTEM_HEADER (t)
-       = in_system_header && (obstack == &permanent_obstack);
+      DECL_USER_ALIGN (t) = 0;
+      DECL_IN_SYSTEM_HEADER (t) = in_system_header;
       DECL_SOURCE_LINE (t) = lineno;
-      DECL_SOURCE_FILE (t) = (input_filename) ? input_filename : "<built-in>";
+      DECL_SOURCE_FILE (t) = 
+       (input_filename) ? input_filename : built_in_filename;
       DECL_UID (t) = next_decl_uid++;
       /* Note that we have not yet computed the alias set for this
         declaration.  */
@@ -1107,6 +1078,7 @@ make_node (code)
     case 't':
       TYPE_UID (t) = next_type_uid++;
       TYPE_ALIGN (t) = 1;
+      TYPE_USER_ALIGN (t) = 0;
       TYPE_MAIN_VARIANT (t) = t;
       TYPE_OBSTACK (t) = obstack;
       TYPE_ATTRIBUTES (t) = NULL_TREE;
@@ -1121,13 +1093,52 @@ make_node (code)
     case 'c':
       TREE_CONSTANT (t) = 1;
       break;
+
+    case 'e':
+      switch (code)
+       {
+       case INIT_EXPR:
+       case MODIFY_EXPR:
+       case VA_ARG_EXPR:
+       case RTL_EXPR:
+       case PREDECREMENT_EXPR:
+       case PREINCREMENT_EXPR:
+       case POSTDECREMENT_EXPR:
+       case POSTINCREMENT_EXPR:
+         /* All of these have side-effects, no matter what their
+            operands are.  */
+         TREE_SIDE_EFFECTS (t) = 1;
+         break;
+         
+       default:
+         break;
+       }
+      break;
     }
 
   return t;
 }
+
+/* A front-end can reset this to an appropriate function if types need
+   special handling.  */
+
+tree (*make_lang_type_fn) PARAMS ((enum tree_code)) = make_node;
+
+/* Return a new type (with the indicated CODE), doing whatever
+   language-specific processing is required.  */
+
+tree 
+make_lang_type (code)
+     enum tree_code code;
+{
+  return (*make_lang_type_fn) (code);
+}
 \f
-/* Return a new node with the same contents as NODE
-   except that its TREE_CHAIN is zero and it has a fresh uid.  */
+/* Return a new node with the same contents as NODE except that its
+   TREE_CHAIN is zero and it has a fresh uid.  Unlike make_node, this
+   function always performs the allocation on the CURRENT_OBSTACK;
+   it's up to the caller to pick the right obstack before calling this
+   function.  */
 
 tree
 copy_node (node)
@@ -1158,11 +1169,11 @@ copy_node (node)
     case '1':  /* a unary arithmetic expression */
     case '2':  /* a binary arithmetic expression */
       length = sizeof (struct tree_exp)
-       + (tree_code_length[(int) code] - 1) * sizeof (char *);
+       + (TREE_CODE_LENGTH (code) - 1) * sizeof (char *);
       break;
 
     case 'c':  /* a constant */
-      /* We can't use tree_code_length for INTEGER_CST, since the number of
+      /* We can't use TREE_CODE_LENGTH for INTEGER_CST, since the number of
         words is machine-dependent due to varying length of HOST_WIDE_INT,
         which might be wider than a pointer (e.g., long long).  Similarly
         for REAL_CST, since the number of words is machine-dependent due
@@ -1173,22 +1184,23 @@ copy_node (node)
        length = sizeof (struct tree_real_cst);
       else
        length = (sizeof (struct tree_common)
-                 + tree_code_length[(int) code] * sizeof (char *));
+                 + TREE_CODE_LENGTH (code) * sizeof (char *));
       break;
 
     case 'x':  /* something random, like an identifier.  */
       length = sizeof (struct tree_common)
-       + tree_code_length[(int) code] * sizeof (char *);
+       + TREE_CODE_LENGTH (code) * sizeof (char *);
       if (code == TREE_VEC)
        length += (TREE_VEC_LENGTH (node) - 1) * sizeof (char *);
     }
 
-  t = (tree) obstack_alloc (current_obstack, length);
+  if (ggc_p)
+    t = ggc_alloc_tree (length);
+  else
+    t = (tree) obstack_alloc (current_obstack, length);
   memcpy (t, node, length);
 
-  /* EXPR_WITH_FILE_LOCATION must keep filename info stored in TREE_CHAIN */
-  if (TREE_CODE (node) != EXPR_WITH_FILE_LOCATION)
-    TREE_CHAIN (t) = 0;
+  TREE_CHAIN (t) = 0;
   TREE_ASM_WRITTEN (t) = 0;
 
   if (TREE_CODE_CLASS (code) == 'd')
@@ -1207,7 +1219,7 @@ copy_node (node)
       TYPE_SYMTAB_ADDRESS (t) = 0;
     }
 
-  TREE_PERMANENT (t) = (current_obstack == &permanent_obstack);
+  TREE_SET_PERMANENT (t);
 
   return t;
 }
@@ -1256,7 +1268,7 @@ get_identifier (text)
 
   /* Decide how much of that length to hash on */
   hash_len = len;
-  if (warn_id_clash && (unsigned)len > id_clash_len)
+  if (warn_id_clash && len > id_clash_len)
     hash_len = id_clash_len;
 
   /* Compute hash code */
@@ -1275,7 +1287,7 @@ get_identifier (text)
       return idp;              /* <-- return if found */
 
   /* Not found; optionally warn about a similar identifier */
-  if (warn_id_clash && do_identifier_warnings && (unsigned)len >= id_clash_len)
+  if (warn_id_clash && do_identifier_warnings && len >= id_clash_len)
     for (idp = hash_table[hi]; idp; idp = TREE_CHAIN (idp))
       if (!strncmp (IDENTIFIER_POINTER (idp), text, id_clash_len))
        {
@@ -1284,7 +1296,7 @@ get_identifier (text)
          break;
        }
 
-  if (tree_code_length[(int) IDENTIFIER_NODE] < 0)
+  if (TREE_CODE_LENGTH (IDENTIFIER_NODE) < 0)
     abort ();                  /* set_identifier_size hasn't been called.  */
 
   /* Not found, create one, add to chain */
@@ -1294,7 +1306,10 @@ get_identifier (text)
   id_string_size += len;
 #endif
 
-  IDENTIFIER_POINTER (idp) = obstack_copy0 (&permanent_obstack, text, len);
+  if (ggc_p)
+    IDENTIFIER_POINTER (idp) = ggc_alloc_string (text, len);
+  else
+    IDENTIFIER_POINTER (idp) = obstack_copy0 (&permanent_obstack, text, len);
 
   TREE_CHAIN (idp) = hash_table[hi];
   hash_table[hi] = idp;
@@ -1319,7 +1334,7 @@ maybe_get_identifier (text)
 
   /* Decide how much of that length to hash on */
   hash_len = len;
-  if (warn_id_clash && (unsigned)len > id_clash_len)
+  if (warn_id_clash && len > id_clash_len)
     hash_len = id_clash_len;
 
   /* Compute hash code */
@@ -1370,9 +1385,11 @@ set_identifier_size (size)
 
 tree
 build_int_2_wide (low, hi)
-     HOST_WIDE_INT low, hi;
+     unsigned HOST_WIDE_INT low;
+     HOST_WIDE_INT hi;
 {
   register tree t = make_node (INTEGER_CST);
+
   TREE_INT_CST_LOW (t) = low;
   TREE_INT_CST_HIGH (t) = hi;
   TREE_TYPE (t) = integer_type_node;
@@ -1409,11 +1426,15 @@ build_real (type, d)
 
 REAL_VALUE_TYPE
 real_value_from_int_cst (type, i)
-     tree type, i;
+     tree type ATTRIBUTE_UNUSED, i;
 {
   REAL_VALUE_TYPE d;
 
 #ifdef REAL_ARITHMETIC
+  /* Clear all bits of the real value type so that we can later do
+     bitwise comparisons to see if two values are the same.  */
+  bzero ((char *) &d, sizeof d);
+
   if (! TREE_UNSIGNED (TREE_TYPE (i)))
     REAL_VALUE_FROM_INT (d, TREE_INT_CST_LOW (i), TREE_INT_CST_HIGH (i),
                         TYPE_MODE (type));
@@ -1431,7 +1452,7 @@ real_value_from_int_cst (type, i)
       e = ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))
            * (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)));
       d *= e;
-      e = (double) (unsigned HOST_WIDE_INT) (~ TREE_INT_CST_LOW (i));
+      e = (double) (~ TREE_INT_CST_LOW (i));
       d += e;
       d = (- d - 1.0);
     }
@@ -1443,38 +1464,44 @@ real_value_from_int_cst (type, i)
       e = ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))
            * (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)));
       d *= e;
-      e = (double) (unsigned HOST_WIDE_INT) TREE_INT_CST_LOW (i);
+      e = (double) TREE_INT_CST_LOW (i);
       d += e;
     }
 #endif /* not REAL_ARITHMETIC */
   return d;
 }
 
+/* Args to pass to and from build_real_from_int_cst_1.  */
+
 struct brfic_args
 {
-  /* Input */
-  tree type, i;
-  /* Output */
-  REAL_VALUE_TYPE d;
+  tree type;                   /* Input: type to conver to. */
+  tree i;                      /* Input: operand to convert */
+  REAL_VALUE_TYPE d;           /* Output: floating point value. */
 };
 
+/* Convert an integer to a floating point value while protected by a floating
+   point exception handler.  */
+
 static void
 build_real_from_int_cst_1 (data)
   PTR data;
 {
-  struct brfic_args * args = (struct brfic_args *) data;
+  struct brfic_args *args = (struct brfic_args *) data;
   
 #ifdef REAL_ARITHMETIC
   args->d = real_value_from_int_cst (args->type, args->i);
 #else
-  args->d =
-    REAL_VALUE_TRUNCATE (TYPE_MODE (args->type),
-                        real_value_from_int_cst (args->type, args->i));
+  args->d
+    REAL_VALUE_TRUNCATE (TYPE_MODE (args->type),
+                          real_value_from_int_cst (args->type, args->i));
 #endif
 }
 
-/* This function can't be implemented if we can't do arithmetic
-   on the float representation.  */
+/* Given a tree representing an integer constant I, return a tree
+   representing the same value as a floating-point constant of type TYPE.
+   We cannot perform this operation if there is no way of doing arithmetic
+   on floating-point values.  */
 
 tree
 build_real_from_int_cst (type, i)
@@ -1494,10 +1521,8 @@ build_real_from_int_cst (type, i)
   args.i = i;
 
   if (do_float_handler (build_real_from_int_cst_1, (PTR) &args))
-    {
-      /* Receive output from build_real_from_int_cst_1() */
-      d = args.d;
-    }
+    /* Receive output from build_real_from_int_cst_1() */
+    d = args.d;
   else
     {
       /* We got an exception from build_real_from_int_cst_1() */
@@ -1532,8 +1557,13 @@ build_string (len, str)
      deferring constant output in varasm.c.  */
 
   register tree s = make_node (STRING_CST);
+
   TREE_STRING_LENGTH (s) = len;
-  TREE_STRING_POINTER (s) = obstack_copy0 (saveable_obstack, str, len);
+  if (ggc_p)
+    TREE_STRING_POINTER (s) = ggc_alloc_string (str, len);
+  else
+    TREE_STRING_POINTER (s) = obstack_copy0 (saveable_obstack, str, len);
+
   return s;
 }
 
@@ -1573,13 +1603,15 @@ make_tree_vec (len)
   tree_node_sizes[(int)vec_kind] += length;
 #endif
 
-  t = (tree) obstack_alloc (obstack, length);
-  bzero ((PTR) t, length);
+  if (ggc_p)
+    t = ggc_alloc_tree (length);
+  else
+    t = (tree) obstack_alloc (obstack, length);
 
+  memset ((PTR) t, 0, length);
   TREE_SET_CODE (t, TREE_VEC);
   TREE_VEC_LENGTH (t) = len;
-  if (obstack == &permanent_obstack)
-    TREE_PERMANENT (t) = 1;
+  TREE_SET_PERMANENT (t);
 
   return t;
 }
@@ -1643,14 +1675,16 @@ integer_all_onesp (expr)
 
   uns = TREE_UNSIGNED (TREE_TYPE (expr));
   if (!uns)
-    return TREE_INT_CST_LOW (expr) == -1 && TREE_INT_CST_HIGH (expr) == -1;
+    return (TREE_INT_CST_LOW (expr) == ~ (unsigned HOST_WIDE_INT) 0
+           && TREE_INT_CST_HIGH (expr) == -1);
 
   /* Note that using TYPE_PRECISION here is wrong.  We care about the
      actual bits, not the (arbitrary) range of the type.  */
   prec = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (expr)));
   if (prec >= HOST_BITS_PER_WIDE_INT)
     {
-      int high_value, shift_amount;
+      HOST_WIDE_INT high_value;
+      int shift_amount;
 
       shift_amount = prec - HOST_BITS_PER_WIDE_INT;
 
@@ -1664,11 +1698,11 @@ integer_all_onesp (expr)
       else
        high_value = ((HOST_WIDE_INT) 1 << shift_amount) - 1;
 
-      return TREE_INT_CST_LOW (expr) == -1
-       && TREE_INT_CST_HIGH (expr) == high_value;
+      return (TREE_INT_CST_LOW (expr) == ~ (unsigned HOST_WIDE_INT) 0
+             && TREE_INT_CST_HIGH (expr) == high_value);
     }
   else
-    return TREE_INT_CST_LOW (expr) == ((HOST_WIDE_INT) 1 << prec) - 1;
+    return TREE_INT_CST_LOW (expr) == ((unsigned HOST_WIDE_INT) 1 << prec) - 1;
 }
 
 /* Return 1 if EXPR is an integer constant that is a power of 2 (i.e., has only
@@ -1756,6 +1790,46 @@ tree_log2 (expr)
          :  exact_log2 (low));
 }
 
+/* Similar, but return the largest integer Y such that 2 ** Y is less
+   than or equal to EXPR.  */
+
+int
+tree_floor_log2 (expr)
+     tree expr;
+{
+  int prec;
+  HOST_WIDE_INT high, low;
+
+  STRIP_NOPS (expr);
+
+  if (TREE_CODE (expr) == COMPLEX_CST)
+    return tree_log2 (TREE_REALPART (expr));
+
+  prec = (POINTER_TYPE_P (TREE_TYPE (expr))
+         ? POINTER_SIZE : TYPE_PRECISION (TREE_TYPE (expr)));
+
+  high = TREE_INT_CST_HIGH (expr);
+  low = TREE_INT_CST_LOW (expr);
+
+  /* First clear all bits that are beyond the type's precision in case
+     we've been sign extended.  Ignore if type's precision hasn't been set
+     since what we are doing is setting it.  */
+
+  if (prec == 2 * HOST_BITS_PER_WIDE_INT || prec == 0)
+    ;
+  else if (prec > HOST_BITS_PER_WIDE_INT)
+    high &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT));
+  else
+    {
+      high = 0;
+      if (prec < HOST_BITS_PER_WIDE_INT)
+       low &= ~((HOST_WIDE_INT) (-1) << prec);
+    }
+
+  return (high != 0 ? HOST_BITS_PER_WIDE_INT + floor_log2 (high)
+         : floor_log2 (low));
+}
+
 /* Return 1 if EXPR is the real constant zero.  */
 
 int
@@ -1883,10 +1957,8 @@ chain_member (elem, chain)
 }
 
 /* Return nonzero if ELEM is equal to TREE_VALUE (CHAIN) for any piece of
-   chain CHAIN.  */
-/* ??? This function was added for machine specific attributes but is no
-   longer used.  It could be deleted if we could confirm all front ends
-   don't use it.  */
+   chain CHAIN.  This and the next function are currently unused, but
+   are retained for completeness.  */
 
 int
 chain_member_value (elem, chain)
@@ -1904,9 +1976,6 @@ chain_member_value (elem, chain)
 
 /* Return nonzero if ELEM is equal to TREE_PURPOSE (CHAIN)
    for any piece of chain CHAIN.  */
-/* ??? This function was added for machine specific attributes but is no
-   longer used.  It could be deleted if we could confirm all front ends
-   don't use it.  */
 
 int
 chain_member_purpose (elem, chain)
@@ -1939,6 +2008,22 @@ list_length (t)
   return len;
 }
 
+/* Returns the number of FIELD_DECLs in TYPE.  */
+
+int
+fields_length (type)
+     tree type;
+{
+  tree t = TYPE_FIELDS (type);
+  int count = 0;
+
+  for (; t; t = TREE_CHAIN (t))
+    if (TREE_CODE (t) == FIELD_DECL)
+      ++count;
+
+  return count;
+}
+
 /* Concatenate two chains of nodes (chained through TREE_CHAIN)
    by modifying the last node in chain 1 to point to chain 2.
    This is the Lisp primitive `nconc'.  */
@@ -1951,14 +2036,18 @@ chainon (op1, op2)
   if (op1)
     {
       register tree t1;
+#ifdef ENABLE_TREE_CHECKING
       register tree t2;
+#endif
 
       for (t1 = op1; TREE_CHAIN (t1); t1 = TREE_CHAIN (t1))
        ;
       TREE_CHAIN (t1) = op2;
+#ifdef ENABLE_TREE_CHECKING
       for (t2 = op2; t2; t2 = TREE_CHAIN (t2))
         if (t2 == t1)
           abort ();  /* Circularity created.  */
+#endif
       return op1;
     }
   else return op2;
@@ -2040,6 +2129,7 @@ build_decl_list (parm, value)
 {
   register tree node;
   register struct obstack *ambient_obstack = current_obstack;
+
   current_obstack = &temp_decl_obstack;
   node = build_tree_list (parm, value);
   current_obstack = ambient_obstack;
@@ -2054,6 +2144,7 @@ build_expr_list (parm, value)
 {
   register tree node;
   register struct obstack *ambient_obstack = current_obstack;
+
   current_obstack = expression_obstack;
   node = build_tree_list (parm, value);
   current_obstack = ambient_obstack;
@@ -2068,23 +2159,22 @@ tree
 tree_cons (purpose, value, chain)
      tree purpose, value, chain;
 {
-#if 0
-  register tree node = make_node (TREE_LIST);
-#else
-  register int i;
-  register tree node = (tree) obstack_alloc (current_obstack, sizeof (struct tree_list));
+  register tree node;
+
+  if (ggc_p)
+    node = ggc_alloc_tree (sizeof (struct tree_list));
+  else
+    node = (tree) obstack_alloc (current_obstack, sizeof (struct tree_list));
+
+  memset (node, 0, sizeof (struct tree_common));
+
 #ifdef GATHER_STATISTICS
-  tree_node_counts[(int)x_kind]++;
-  tree_node_sizes[(int)x_kind] += sizeof (struct tree_list);
+  tree_node_counts[(int) x_kind]++;
+  tree_node_sizes[(int) x_kind] += sizeof (struct tree_list);
 #endif
 
-  for (i = (sizeof (struct tree_common) / sizeof (int)) - 1; i >= 0; i--)
-    ((int *) node)[i] = 0;
-
   TREE_SET_CODE (node, TREE_LIST);
-  if (current_obstack == &permanent_obstack)
-    TREE_PERMANENT (node) = 1;
-#endif
+  TREE_SET_PERMANENT (node);
 
   TREE_CHAIN (node) = chain;
   TREE_PURPOSE (node) = purpose;
@@ -2100,6 +2190,7 @@ decl_tree_cons (purpose, value, chain)
 {
   register tree node;
   register struct obstack *ambient_obstack = current_obstack;
+
   current_obstack = &temp_decl_obstack;
   node = tree_cons (purpose, value, chain);
   current_obstack = ambient_obstack;
@@ -2114,6 +2205,7 @@ expr_tree_cons (purpose, value, chain)
 {
   register tree node;
   register struct obstack *ambient_obstack = current_obstack;
+
   current_obstack = expression_obstack;
   node = tree_cons (purpose, value, chain);
   current_obstack = ambient_obstack;
@@ -2128,8 +2220,8 @@ perm_tree_cons (purpose, value, chain)
 {
   register tree node;
   register struct obstack *ambient_obstack = current_obstack;
-  current_obstack = &permanent_obstack;
 
+  current_obstack = &permanent_obstack;
   node = tree_cons (purpose, value, chain);
   current_obstack = ambient_obstack;
   return node;
@@ -2143,8 +2235,8 @@ temp_tree_cons (purpose, value, chain)
 {
   register tree node;
   register struct obstack *ambient_obstack = current_obstack;
-  current_obstack = &temporary_obstack;
 
+  current_obstack = &temporary_obstack;
   node = tree_cons (purpose, value, chain);
   current_obstack = ambient_obstack;
   return node;
@@ -2158,8 +2250,8 @@ saveable_tree_cons (purpose, value, chain)
 {
   register tree node;
   register struct obstack *ambient_obstack = current_obstack;
-  current_obstack = saveable_obstack;
 
+  current_obstack = saveable_obstack;
   node = tree_cons (purpose, value, chain);
   current_obstack = ambient_obstack;
   return node;
@@ -2182,11 +2274,13 @@ size_in_bytes (type)
 
   type = TYPE_MAIN_VARIANT (type);
   t = TYPE_SIZE_UNIT (type);
+
   if (t == 0)
     {
       incomplete_type_error (NULL_TREE, type);
-      return integer_zero_node;
+      return size_zero_node;
     }
+
   if (TREE_CODE (t) == INTEGER_CST)
     force_fit_type (t, 0);
 
@@ -2209,17 +2303,109 @@ int_size_in_bytes (type)
   t = TYPE_SIZE_UNIT (type);
   if (t == 0
       || TREE_CODE (t) != INTEGER_CST
-      || TREE_INT_CST_HIGH (t) != 0)
+      || TREE_OVERFLOW (t)
+      || TREE_INT_CST_HIGH (t) != 0
+      /* If the result would appear negative, it's too big to represent.  */
+      || (HOST_WIDE_INT) TREE_INT_CST_LOW (t) < 0)
     return -1;
 
   return TREE_INT_CST_LOW (t);
 }
 \f
-/* Return, as a tree node, the number of elements for TYPE (which is an
-   ARRAY_TYPE) minus one. This counts only elements of the top array.
+/* Return the bit position of FIELD, in bits from the start of the record.
+   This is a tree of type bitsizetype.  */
+
+tree
+bit_position (field)
+     tree field;
+{
+
+  return bit_from_pos (DECL_FIELD_OFFSET (field),
+                      DECL_FIELD_BIT_OFFSET (field));
+}
+
+/* Likewise, but return as an integer.  Abort if it cannot be represented
+   in that way (since it could be a signed value, we don't have the option
+   of returning -1 like int_size_in_byte can.  */
+
+HOST_WIDE_INT
+int_bit_position (field)
+     tree field;
+{
+  return tree_low_cst (bit_position (field), 0);
+}
+\f
+/* Return the byte position of FIELD, in bytes from the start of the record.
+   This is a tree of type sizetype.  */
+
+tree
+byte_position (field)
+     tree field;
+{
+  return byte_from_pos (DECL_FIELD_OFFSET (field),
+                       DECL_FIELD_BIT_OFFSET (field));
+}
 
-   Don't let any SAVE_EXPRs escape; if we are called as part of a cleanup
-   action, they would get unsaved.  */
+/* Likewise, but return as an integer.  Abort if it cannot be represented
+   in that way (since it could be a signed value, we don't have the option
+   of returning -1 like int_size_in_byte can.  */
+
+HOST_WIDE_INT
+int_byte_position (field)
+     tree field;
+{
+  return tree_low_cst (byte_position (field), 0);
+}
+\f
+/* Return the strictest alignment, in bits, that T is known to have.  */
+
+unsigned int
+expr_align (t)
+     tree t;
+{
+  unsigned int align0, align1;
+
+  switch (TREE_CODE (t))
+    {
+    case NOP_EXPR:  case CONVERT_EXPR:  case NON_LVALUE_EXPR:
+      /* If we have conversions, we know that the alignment of the
+        object must meet each of the alignments of the types.  */
+      align0 = expr_align (TREE_OPERAND (t, 0));
+      align1 = TYPE_ALIGN (TREE_TYPE (t));
+      return MAX (align0, align1);
+
+    case SAVE_EXPR:         case COMPOUND_EXPR:       case MODIFY_EXPR:
+    case INIT_EXPR:         case TARGET_EXPR:         case WITH_CLEANUP_EXPR:
+    case WITH_RECORD_EXPR:  case CLEANUP_POINT_EXPR:  case UNSAVE_EXPR:
+      /* These don't change the alignment of an object.  */
+      return expr_align (TREE_OPERAND (t, 0));
+
+    case COND_EXPR:
+      /* The best we can do is say that the alignment is the least aligned
+        of the two arms.  */
+      align0 = expr_align (TREE_OPERAND (t, 1));
+      align1 = expr_align (TREE_OPERAND (t, 2));
+      return MIN (align0, align1);
+
+    case LABEL_DECL:     case CONST_DECL:
+    case VAR_DECL:       case PARM_DECL:   case RESULT_DECL:
+      if (DECL_ALIGN (t) != 0)
+       return DECL_ALIGN (t);
+      break;
+
+    case FUNCTION_DECL:
+      return FUNCTION_BOUNDARY;
+
+    default:
+      break;
+    }
+
+  /* Otherwise take the alignment from that of the type.  */
+  return TYPE_ALIGN (TREE_TYPE (t));
+}
+\f
+/* Return, as a tree node, the number of elements for TYPE (which is an
+   ARRAY_TYPE) minus one. This counts only elements of the top array.  */
 
 tree
 array_type_nelts (type)
@@ -2236,26 +2422,6 @@ array_type_nelts (type)
   min = TYPE_MIN_VALUE (index_type);
   max = TYPE_MAX_VALUE (index_type);
 
-  if (! TREE_CONSTANT (min))
-    {
-      STRIP_NOPS (min);
-      if (TREE_CODE (min) == SAVE_EXPR)
-       min = build (RTL_EXPR, TREE_TYPE (TYPE_MIN_VALUE (index_type)), 0,
-                    SAVE_EXPR_RTL (min));
-      else
-       min = TYPE_MIN_VALUE (index_type);
-    }
-
-  if (! TREE_CONSTANT (max))
-    {
-      STRIP_NOPS (max);
-      if (TREE_CODE (max) == SAVE_EXPR)
-       max = build (RTL_EXPR, TREE_TYPE (TYPE_MAX_VALUE (index_type)), 0,
-                    SAVE_EXPR_RTL (max));
-      else
-       max = TYPE_MAX_VALUE (index_type);
-    }
-
   return (integer_zerop (min)
          ? max
          : fold (build (MINUS_EXPR, TREE_TYPE (max), max, min)));
@@ -2273,16 +2439,17 @@ staticp (arg)
     case FUNCTION_DECL:
       /* Nested functions aren't static, since taking their address
         involves a trampoline.  */
-       return (decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg))
-              && ! DECL_NON_ADDR_CONST_P (arg);
+      return (decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg))
+       && ! DECL_NON_ADDR_CONST_P (arg);
 
     case VAR_DECL:
       return (TREE_STATIC (arg) || DECL_EXTERNAL (arg))
-             && ! DECL_NON_ADDR_CONST_P (arg);
+       && ! DECL_NON_ADDR_CONST_P (arg);
 
     case CONSTRUCTOR:
       return TREE_STATIC (arg);
 
+    case LABEL_DECL:
     case STRING_CST:
       return 1;
 
@@ -2418,33 +2585,32 @@ first_rtl_op (code)
     case METHOD_CALL_EXPR:
       return 3;
     default:
-      return tree_code_length [(int) code];
+      return TREE_CODE_LENGTH (code);
     }
 }
 
-/* Modify a tree in place so that all the evaluate only once things
-   are cleared out.  Return the EXPR given.  */
+/* Perform any modifications to EXPR required when it is unsaved.  Does
+   not recurse into EXPR's subtrees.  */
 
-tree
-unsave_expr_now (expr)
+void
+unsave_expr_1 (expr)
      tree expr;
 {
-  enum tree_code code;
-  register int i;
-  int first_rtl;
-
-  if (expr == NULL_TREE)
-    return expr;
-
-  code = TREE_CODE (expr);
-  first_rtl = first_rtl_op (code);
-  switch (code)
+  switch (TREE_CODE (expr))
     {
     case SAVE_EXPR:
-      SAVE_EXPR_RTL (expr) = 0;
+      if (! SAVE_EXPR_PERSISTENT_P (expr))
+       SAVE_EXPR_RTL (expr) = 0;
       break;
 
     case TARGET_EXPR:
+      /* Don't mess with a TARGET_EXPR that hasn't been expanded.
+         It's OK for this to happen if it was part of a subtree that
+         isn't immediately expanded, such as operand 2 of another
+         TARGET_EXPR.  */
+      if (TREE_OPERAND (expr, 1))
+       break;
+
       TREE_OPERAND (expr, 1) = TREE_OPERAND (expr, 3);
       TREE_OPERAND (expr, 3) = NULL_TREE;
       break;
@@ -2457,30 +2623,45 @@ unsave_expr_now (expr)
 
     case CALL_EXPR:
       CALL_EXPR_RTL (expr) = 0;
-      if (TREE_OPERAND (expr, 1)
-         && TREE_CODE (TREE_OPERAND (expr, 1)) == TREE_LIST)
-       {
-         tree exp = TREE_OPERAND (expr, 1);
-         while (exp)
-           {
-             unsave_expr_now (TREE_VALUE (exp));
-             exp = TREE_CHAIN (exp);
-           }
-       }
       break;
 
     default:
+      if (lang_unsave_expr_now != 0)
+       (*lang_unsave_expr_now) (expr);
       break;
     }
+}
+
+/* Helper function for unsave_expr_now.  */
+
+static void
+unsave_expr_now_r (expr)
+     tree expr;
+{
+  enum tree_code code;
+
+  /* There's nothing to do for NULL_TREE.  */
+  if (expr == 0)
+    return;
 
+  unsave_expr_1 (expr);
+
+  code = TREE_CODE (expr);
   switch (TREE_CODE_CLASS (code))
     {
     case 'c':  /* a constant */
     case 't':  /* a type node */
-    case 'x':  /* something random, like an identifier or an ERROR_MARK.  */
     case 'd':  /* A decl node */
     case 'b':  /* A block node */
-      return expr;
+      break;
+
+    case 'x':  /* miscellaneous: e.g., identifier, TREE_LIST or ERROR_MARK.  */
+      if (code == TREE_LIST)
+       {
+         unsave_expr_now_r (TREE_VALUE (expr));
+         unsave_expr_now_r (TREE_CHAIN (expr));
+       }
+      break;
 
     case 'e':  /* an expression */
     case 'r':  /* a reference */
@@ -2488,35 +2669,142 @@ unsave_expr_now (expr)
     case '<':  /* a comparison expression */
     case '2':  /* a binary arithmetic expression */
     case '1':  /* a unary arithmetic expression */
-      for (i = first_rtl - 1; i >= 0; i--)
-       unsave_expr_now (TREE_OPERAND (expr, i));
-      return expr;
+      {
+       int i;
+       
+       for (i = first_rtl_op (code) - 1; i >= 0; i--)
+         unsave_expr_now_r (TREE_OPERAND (expr, i));
+      }
+      break;
 
     default:
       abort ();
     }
 }
-\f
-/* Return 1 if EXP contains a PLACEHOLDER_EXPR; i.e., if it represents a size
-   or offset that depends on a field within a record.  */
 
-int
-contains_placeholder_p (exp)
-     tree exp;
+/* Modify a tree in place so that all the evaluate only once things
+   are cleared out.  Return the EXPR given.  */
+
+tree
+unsave_expr_now (expr)
+     tree expr;
 {
-  register enum tree_code code = TREE_CODE (exp);
-  int result;
+  if (lang_unsave!= 0)
+    (*lang_unsave) (&expr);
+  else
+    unsave_expr_now_r (expr);
 
-  /* If we have a WITH_RECORD_EXPR, it "cancels" any PLACEHOLDER_EXPR
-     in it since it is supplying a value for it.  */
-  if (code == WITH_RECORD_EXPR)
-    return 0;
-  else if (code == PLACEHOLDER_EXPR)
-    return 1;
+  return expr;
+}
 
-  switch (TREE_CODE_CLASS (code))
-    {
-    case 'r':
+/* Return 0 if it is safe to evaluate EXPR multiple times,
+   return 1 if it is safe if EXPR is unsaved afterward, or
+   return 2 if it is completely unsafe. 
+
+   This assumes that CALL_EXPRs and TARGET_EXPRs are never replicated in
+   an expression tree, so that it safe to unsave them and the surrounding
+   context will be correct.
+
+   SAVE_EXPRs basically *only* appear replicated in an expression tree,
+   occasionally across the whole of a function.  It is therefore only
+   safe to unsave a SAVE_EXPR if you know that all occurrences appear
+   below the UNSAVE_EXPR.
+
+   RTL_EXPRs consume their rtl during evaluation.  It is therefore 
+   never possible to unsave them.  */
+
+int
+unsafe_for_reeval (expr)
+     tree expr;
+{
+  int unsafeness = 0;
+  enum tree_code code;
+  int i, tmp;
+  tree exp;
+  int first_rtl;
+
+  if (expr == NULL_TREE)
+    return 1;
+
+  code = TREE_CODE (expr);
+  first_rtl = first_rtl_op (code);
+
+  switch (code)
+    {
+    case SAVE_EXPR:
+    case RTL_EXPR:
+      return 2;
+
+    case TREE_LIST:
+      for (exp = expr; exp != 0; exp = TREE_CHAIN (exp))
+       {
+         tmp = unsafe_for_reeval (TREE_VALUE (exp));
+         unsafeness = MAX (tmp, unsafeness);
+       }
+
+      return unsafeness;
+
+    case CALL_EXPR:
+      tmp = unsafe_for_reeval (TREE_OPERAND (expr, 1));
+      return MAX (tmp, 1);
+
+    case TARGET_EXPR:
+      unsafeness = 1;
+      break;
+
+    default:
+      /* ??? Add a lang hook if it becomes necessary.  */
+      break;
+    }
+
+  switch (TREE_CODE_CLASS (code))
+    {
+    case 'c':  /* a constant */
+    case 't':  /* a type node */
+    case 'x':  /* something random, like an identifier or an ERROR_MARK.  */
+    case 'd':  /* A decl node */
+    case 'b':  /* A block node */
+      return 0;
+
+    case 'e':  /* an expression */
+    case 'r':  /* a reference */
+    case 's':  /* an expression with side effects */
+    case '<':  /* a comparison expression */
+    case '2':  /* a binary arithmetic expression */
+    case '1':  /* a unary arithmetic expression */
+      for (i = first_rtl - 1; i >= 0; i--)
+       {
+         tmp = unsafe_for_reeval (TREE_OPERAND (expr, i));
+         unsafeness = MAX (tmp, unsafeness);
+       }
+
+      return unsafeness;
+
+    default:
+      return 2;
+    }
+}
+\f
+/* Return 1 if EXP contains a PLACEHOLDER_EXPR; i.e., if it represents a size
+   or offset that depends on a field within a record.  */
+
+int
+contains_placeholder_p (exp)
+     tree exp;
+{
+  register enum tree_code code = TREE_CODE (exp);
+  int result;
+
+  /* If we have a WITH_RECORD_EXPR, it "cancels" any PLACEHOLDER_EXPR
+     in it since it is supplying a value for it.  */
+  if (code == WITH_RECORD_EXPR)
+    return 0;
+  else if (code == PLACEHOLDER_EXPR)
+    return 1;
+
+  switch (TREE_CODE_CLASS (code))
+    {
+    case 'r':
       /* Don't look at any PLACEHOLDER_EXPRs that might be in index or bit
         position computations since they will be converted into a
         WITH_RECORD_EXPR involving the reference, which will assume
@@ -2569,7 +2857,7 @@ contains_placeholder_p (exp)
          break;
        }
 
-      switch (tree_code_length[(int) code])
+      switch (TREE_CODE_LENGTH (code))
        {
        case 1:
          return contains_placeholder_p (TREE_OPERAND (exp, 0));
@@ -2688,7 +2976,7 @@ substitute_in_expr (exp, f, r)
     case '2':
     case '<':
     case 'e':
-      switch (tree_code_length[(int) code])
+      switch (TREE_CODE_LENGTH (code))
        {
        case 1:
          op0 = substitute_in_expr (TREE_OPERAND (exp, 0), f, r);
@@ -2894,7 +3182,6 @@ stabilize_reference (ref)
   TREE_READONLY (result) = TREE_READONLY (ref);
   TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (ref);
   TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (ref);
-  TREE_RAISES (result) = TREE_RAISES (ref);
 
   return result;
 }
@@ -2977,7 +3264,6 @@ stabilize_reference_1 (e)
   TREE_READONLY (result) = TREE_READONLY (e);
   TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (e);
   TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e);
-  TREE_RAISES (result) = TREE_RAISES (e);
 
   return result;
 }
@@ -2990,7 +3276,7 @@ stabilize_reference_1 (e)
    Constants, decls, types and misc nodes cannot be.  */
 
 tree
-build VPROTO((enum tree_code code, tree tt, ...))
+build VPARAMS ((enum tree_code code, tree tt, ...))
 {
 #ifndef ANSI_PROTOTYPES
   enum tree_code code;
@@ -3000,6 +3286,7 @@ build VPROTO((enum tree_code code, tree tt, ...))
   register tree t;
   register int length;
   register int i;
+  int fro;
 
   VA_START (p, tt);
 
@@ -3009,9 +3296,15 @@ build VPROTO((enum tree_code code, tree tt, ...))
 #endif
 
   t = make_node (code);
-  length = tree_code_length[(int) code];
+  length = TREE_CODE_LENGTH (code);
   TREE_TYPE (t) = tt;
 
+  /* Below, we automatically set TREE_SIDE_EFFECTS and TREE_RAISED for
+     the result based on those same flags for the arguments.  But, if
+     the arguments aren't really even `tree' expressions, we shouldn't
+     be trying to do this.  */
+  fro = first_rtl_op (code);
+
   if (length == 2)
     {
       /* This is equivalent to the loop below, but faster.  */
@@ -3019,11 +3312,16 @@ build VPROTO((enum tree_code code, tree tt, ...))
       register tree arg1 = va_arg (p, tree);
       TREE_OPERAND (t, 0) = arg0;
       TREE_OPERAND (t, 1) = arg1;
-      if ((arg0 && TREE_SIDE_EFFECTS (arg0))
-         || (arg1 && TREE_SIDE_EFFECTS (arg1)))
-       TREE_SIDE_EFFECTS (t) = 1;
-      TREE_RAISES (t)
-       = (arg0 && TREE_RAISES (arg0)) || (arg1 && TREE_RAISES (arg1));
+      if (arg0 && fro > 0)
+       {
+         if (TREE_SIDE_EFFECTS (arg0))
+           TREE_SIDE_EFFECTS (t) = 1;
+       }
+      if (arg1 && fro > 1)
+       {
+         if (TREE_SIDE_EFFECTS (arg1))
+           TREE_SIDE_EFFECTS (t) = 1;
+       }
     }
   else if (length == 1)
     {
@@ -3033,9 +3331,11 @@ build VPROTO((enum tree_code code, tree tt, ...))
       if (TREE_CODE_CLASS (code) != 's')
        abort ();
       TREE_OPERAND (t, 0) = arg0;
-      if (arg0 && TREE_SIDE_EFFECTS (arg0))
-       TREE_SIDE_EFFECTS (t) = 1;
-      TREE_RAISES (t) = (arg0 && TREE_RAISES (arg0));
+      if (fro > 0)
+       {
+         if (arg0 && TREE_SIDE_EFFECTS (arg0))
+           TREE_SIDE_EFFECTS (t) = 1;
+       }
     }
   else
     {
@@ -3043,12 +3343,10 @@ build VPROTO((enum tree_code code, tree tt, ...))
        {
          register tree operand = va_arg (p, tree);
          TREE_OPERAND (t, i) = operand;
-         if (operand)
+         if (operand && fro > i)
            {
              if (TREE_SIDE_EFFECTS (operand))
                TREE_SIDE_EFFECTS (t) = 1;
-             if (TREE_RAISES (operand))
-               TREE_RAISES (t) = 1;
            }
        }
     }
@@ -3082,27 +3380,44 @@ build1 (code, type, node)
 
   length = sizeof (struct tree_exp);
 
-  t = (tree) obstack_alloc (obstack, length);
-  bzero ((PTR) t, length);
+  if (ggc_p)
+    t = ggc_alloc_tree (length);
+  else
+    t = (tree) obstack_alloc (obstack, length);
+
+  memset ((PTR) t, 0, sizeof (struct tree_common));
 
 #ifdef GATHER_STATISTICS
   tree_node_counts[(int)kind]++;
   tree_node_sizes[(int)kind] += length;
 #endif
 
-  TREE_TYPE (t) = type;
   TREE_SET_CODE (t, code);
+  TREE_SET_PERMANENT (t);
 
-  if (obstack == &permanent_obstack)
-    TREE_PERMANENT (t) = 1;
-
+  TREE_TYPE (t) = type;
+  TREE_COMPLEXITY (t) = 0;
   TREE_OPERAND (t, 0) = node;
-  if (node)
+  if (node && first_rtl_op (code) != 0 && TREE_SIDE_EFFECTS (node))
+    TREE_SIDE_EFFECTS (t) = 1;
+
+  switch (code)
     {
-      if (TREE_SIDE_EFFECTS (node))
-       TREE_SIDE_EFFECTS (t) = 1;
-      if (TREE_RAISES (node))
-       TREE_RAISES (t) = 1;
+    case INIT_EXPR:
+    case MODIFY_EXPR:
+    case VA_ARG_EXPR:
+    case RTL_EXPR:
+    case PREDECREMENT_EXPR:
+    case PREINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+      /* All of these have side-effects, no matter what their
+        operands are.  */
+      TREE_SIDE_EFFECTS (t) = 1;
+      break;
+         
+    default:
+      break;
     }
 
   return t;
@@ -3114,7 +3429,7 @@ build1 (code, type, node)
    or even garbage if their values do not matter.  */
 
 tree
-build_nt VPROTO((enum tree_code code, ...))
+build_nt VPARAMS ((enum tree_code code, ...))
 {
 #ifndef ANSI_PROTOTYPES
   enum tree_code code;
@@ -3131,7 +3446,7 @@ build_nt VPROTO((enum tree_code code, ...))
 #endif
 
   t = make_node (code);
-  length = tree_code_length[(int) code];
+  length = TREE_CODE_LENGTH (code);
 
   for (i = 0; i < length; i++)
     TREE_OPERAND (t, i) = va_arg (p, tree);
@@ -3144,7 +3459,7 @@ build_nt VPROTO((enum tree_code code, ...))
    on the temp_decl_obstack, regardless.  */
 
 tree
-build_parse_node VPROTO((enum tree_code code, ...))
+build_parse_node VPARAMS ((enum tree_code code, ...))
 {
 #ifndef ANSI_PROTOTYPES
   enum tree_code code;
@@ -3164,7 +3479,7 @@ build_parse_node VPROTO((enum tree_code code, ...))
   expression_obstack = &temp_decl_obstack;
 
   t = make_node (code);
-  length = tree_code_length[(int) code];
+  length = TREE_CODE_LENGTH (code);
 
   for (i = 0; i < length; i++)
     TREE_OPERAND (t, i) = va_arg (p, tree);
@@ -3226,11 +3541,11 @@ build_decl (code, name, type)
 
 tree
 build_block (vars, tags, subblocks, supercontext, chain)
-     tree vars, tags, subblocks, supercontext, chain;
+     tree vars, tags ATTRIBUTE_UNUSED, subblocks, supercontext, chain;
 {
   register tree block = make_node (BLOCK);
+
   BLOCK_VARS (block) = vars;
-  BLOCK_TYPE_TAGS (block) = tags;
   BLOCK_SUBBLOCKS (block) = subblocks;
   BLOCK_SUPERCONTEXT (block) = supercontext;
   BLOCK_CHAIN (block) = chain;
@@ -3249,7 +3564,7 @@ build_expr_wfl (node, file, line, col)
      int line, col;
 {
   static const char *last_file = 0;
-  static tree  last_filenode = NULL_TREE;
+  static tree last_filenode = NULL_TREE;
   register tree wfl = make_node (EXPR_WITH_FILE_LOCATION);
 
   EXPR_WFL_NODE (wfl) = node;
@@ -3259,12 +3574,14 @@ build_expr_wfl (node, file, line, col)
       last_file = file;
       last_filenode = file ? get_identifier (file) : NULL_TREE;
     }
+
   EXPR_WFL_FILENAME_NODE (wfl) = last_filenode;
   if (node)
     {
       TREE_SIDE_EFFECTS (wfl) = TREE_SIDE_EFFECTS (node);
       TREE_TYPE (wfl) = TREE_TYPE (node);
     }
+
   return wfl;
 }
 \f
@@ -3290,15 +3607,11 @@ build_type_attribute_variant (ttype, attribute)
 {
   if ( ! attribute_list_equal (TYPE_ATTRIBUTES (ttype), attribute))
     {
-      register int hashcode;
-      register struct obstack *ambient_obstack = current_obstack;
+      unsigned int hashcode;
       tree ntype;
 
-      if (ambient_obstack != &permanent_obstack)
-        current_obstack = TYPE_OBSTACK (ttype);
-
+      push_obstacks (TYPE_OBSTACK (ttype), TYPE_OBSTACK (ttype));
       ntype = copy_node (ttype);
-      current_obstack = ambient_obstack;
 
       TYPE_POINTER_TO (ntype) = 0;
       TYPE_REFERENCE_TO (ntype) = 0;
@@ -3309,9 +3622,9 @@ build_type_attribute_variant (ttype, attribute)
       TYPE_NEXT_VARIANT (ntype) = 0;
       set_type_quals (ntype, TYPE_UNQUALIFIED);
 
-      hashcode = TYPE_HASH (TREE_CODE (ntype))
-                + TYPE_HASH (TREE_TYPE (ntype))
-                + attribute_hash_list (attribute);
+      hashcode = (TYPE_HASH (TREE_CODE (ntype))
+                 + TYPE_HASH (TREE_TYPE (ntype))
+                 + attribute_hash_list (attribute));
 
       switch (TREE_CODE (ntype))
         {
@@ -3333,6 +3646,7 @@ build_type_attribute_variant (ttype, attribute)
 
       ntype = type_hash_canon (hashcode, ntype);
       ttype = build_qualified_type (ntype, TYPE_QUALS (ttype));
+      pop_obstacks ();
     }
 
   return ttype;
@@ -3362,7 +3676,8 @@ valid_machine_attribute (attr_name, attr_args, decl, type)
 
 #ifdef VALID_MACHINE_DECL_ATTRIBUTE
   if (decl != 0
-      && VALID_MACHINE_DECL_ATTRIBUTE (decl, decl_attr_list, attr_name, attr_args))
+      && VALID_MACHINE_DECL_ATTRIBUTE (decl, decl_attr_list, attr_name,
+                                      attr_args))
     {
       tree attr = lookup_attribute (IDENTIFIER_POINTER (attr_name),
                                    decl_attr_list);
@@ -3411,8 +3726,10 @@ valid_machine_attribute (attr_name, attr_args, decl, type)
          else
            TYPE_ATTRIBUTES (type) = type_attr_list;
        }
+
       if (decl != 0)
        TREE_TYPE (decl) = type;
+
       validated = 1;
     }
 
@@ -3535,12 +3852,12 @@ merge_attributes (a1, a2)
 
   /* Either one unset?  Take the set one.  */
 
-  if (! (attributes = a1))
+  if ((attributes = a1) == 0)
     attributes = a2;
 
   /* One that completely contains the other?  Take it.  */
 
-  else if (a2 && ! attribute_list_contained (a1, a2))
+  else if (a2 != 0 && ! attribute_list_contained (a1, a2))
   {
     if (attribute_list_contained (a2, a1))
       attributes = a2;
@@ -3552,7 +3869,7 @@ merge_attributes (a1, a2)
        if (list_length (a1) < list_length (a2))
          attributes = a2, a2 = a1;
 
-       for (; a2; a2 = TREE_CHAIN (a2))
+       for (; a2 != 0; a2 = TREE_CHAIN (a2))
          if (lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
                                attributes) == NULL_TREE)
            {
@@ -3663,72 +3980,87 @@ build_type_copy (type)
 /* Hashing of types so that we don't make duplicates.
    The entry point is `type_hash_canon'.  */
 
-/* Each hash table slot is a bucket containing a chain
-   of these structures.  */
-
-struct type_hash
-{
-  struct type_hash *next;      /* Next structure in the bucket.  */
-  int hashcode;                        /* Hash code of this type.  */
-  tree type;                   /* The type recorded here.  */
-};
-
-/* Now here is the hash table.  When recording a type, it is added
-   to the slot whose index is the hash code mod the table size.
-   Note that the hash table is used for several kinds of types
-   (function types, array types and array index range types, for now).
-   While all these live in the same table, they are completely independent,
-   and the hash code is computed differently for each of these.  */
-
-#define TYPE_HASH_SIZE 59
-struct type_hash *type_hash_table[TYPE_HASH_SIZE];
-
 /* Compute a hash code for a list of types (chain of TREE_LIST nodes
    with types in the TREE_VALUE slots), by adding the hash codes
    of the individual types.  */
 
-int
+unsigned int
 type_hash_list (list)
      tree list;
 {
-  register int hashcode;
+  unsigned int hashcode;
   register tree tail;
+
   for (hashcode = 0, tail = list; tail; tail = TREE_CHAIN (tail))
     hashcode += TYPE_HASH (TREE_VALUE (tail));
+
   return hashcode;
 }
 
+/* These are the Hashtable callback functions.  */
+
+/* Returns true if the types are equal.  */
+
+static int
+type_hash_eq (va, vb)
+     const void *va;
+     const void *vb;
+{
+  const struct type_hash *a = va, *b = vb;
+  if (a->hash == b->hash
+      && TREE_CODE (a->type) == TREE_CODE (b->type)
+      && TREE_TYPE (a->type) == TREE_TYPE (b->type)
+      && attribute_list_equal (TYPE_ATTRIBUTES (a->type),
+                              TYPE_ATTRIBUTES (b->type))
+      && TYPE_ALIGN (a->type) == TYPE_ALIGN (b->type)
+      && (TYPE_MAX_VALUE (a->type) == TYPE_MAX_VALUE (b->type)
+         || tree_int_cst_equal (TYPE_MAX_VALUE (a->type),
+                                TYPE_MAX_VALUE (b->type)))
+      && (TYPE_MIN_VALUE (a->type) == TYPE_MIN_VALUE (b->type)
+         || tree_int_cst_equal (TYPE_MIN_VALUE (a->type),
+                                TYPE_MIN_VALUE (b->type)))
+      /* Note that TYPE_DOMAIN is TYPE_ARG_TYPES for FUNCTION_TYPE.  */
+      && (TYPE_DOMAIN (a->type) == TYPE_DOMAIN (b->type)
+         || (TYPE_DOMAIN (a->type)
+             && TREE_CODE (TYPE_DOMAIN (a->type)) == TREE_LIST
+             && TYPE_DOMAIN (b->type)
+             && TREE_CODE (TYPE_DOMAIN (b->type)) == TREE_LIST
+             && type_list_equal (TYPE_DOMAIN (a->type),
+                                 TYPE_DOMAIN (b->type)))))
+    return 1;
+  return 0;
+}
+
+/* Return the cached hash value.  */
+
+static unsigned int
+type_hash_hash (item)
+     const void *item;
+{
+  return ((const struct type_hash*)item)->hash;
+}
+
 /* Look in the type hash table for a type isomorphic to TYPE.
    If one is found, return it.  Otherwise return 0.  */
 
 tree
 type_hash_lookup (hashcode, type)
-     int hashcode;
+     unsigned int hashcode;
      tree type;
 {
-  register struct type_hash *h;
-  for (h = type_hash_table[hashcode % TYPE_HASH_SIZE]; h; h = h->next)
-    if (h->hashcode == hashcode
-       && TREE_CODE (h->type) == TREE_CODE (type)
-       && TREE_TYPE (h->type) == TREE_TYPE (type)
-        && attribute_list_equal (TYPE_ATTRIBUTES (h->type),
-                                  TYPE_ATTRIBUTES (type))
-       && (TYPE_MAX_VALUE (h->type) == TYPE_MAX_VALUE (type)
-           || tree_int_cst_equal (TYPE_MAX_VALUE (h->type),
-                                  TYPE_MAX_VALUE (type)))
-       && (TYPE_MIN_VALUE (h->type) == TYPE_MIN_VALUE (type)
-           || tree_int_cst_equal (TYPE_MIN_VALUE (h->type),
-                                  TYPE_MIN_VALUE (type)))
-       /* Note that TYPE_DOMAIN is TYPE_ARG_TYPES for FUNCTION_TYPE.  */
-       && (TYPE_DOMAIN (h->type) == TYPE_DOMAIN (type)
-           || (TYPE_DOMAIN (h->type)
-               && TREE_CODE (TYPE_DOMAIN (h->type)) == TREE_LIST
-               && TYPE_DOMAIN (type)
-               && TREE_CODE (TYPE_DOMAIN (type)) == TREE_LIST
-               && type_list_equal (TYPE_DOMAIN (h->type),
-                                   TYPE_DOMAIN (type)))))
-      return h->type;
-  return 0;
+  struct type_hash *h, in;
+
+  /* The TYPE_ALIGN field of a type is set by layout_type(), so we
+     must call that routine before comparing TYPE_ALIGNs. */
+  layout_type (type);
+
+  in.hash = hashcode;
+  in.type = type;
+
+  h = htab_find_with_hash (type_hash_table, &in, hashcode);
+  if (h)
+    return h->type;
+  return NULL_TREE;
 }
 
 /* Add an entry to the type-hash-table
@@ -3736,16 +4068,17 @@ type_hash_lookup (hashcode, type)
 
 void
 type_hash_add (hashcode, type)
-     int hashcode;
+     unsigned int hashcode;
      tree type;
 {
-  register struct type_hash *h;
+  struct type_hash *h;
+  void **loc;
 
-  h = (struct type_hash *) oballoc (sizeof (struct type_hash));
-  h->hashcode = hashcode;
+  h = (struct type_hash *) permalloc (sizeof (struct type_hash));
+  h->hash = hashcode;
   h->type = type;
-  h->next = type_hash_table[hashcode % TYPE_HASH_SIZE];
-  type_hash_table[hashcode % TYPE_HASH_SIZE] = h;
+  loc = htab_find_slot_with_hash (type_hash_table, h, hashcode, INSERT);
+  *(struct type_hash**) loc = h;
 }
 
 /* Given TYPE, and HASHCODE its hash code, return the canonical
@@ -3764,7 +4097,7 @@ int debug_no_type_hash = 0;
 
 tree
 type_hash_canon (hashcode, type)
-     int hashcode;
+     unsigned int hashcode;
      tree type;
 {
   tree t1;
@@ -3775,31 +4108,69 @@ type_hash_canon (hashcode, type)
   t1 = type_hash_lookup (hashcode, type);
   if (t1 != 0)
     {
-      obstack_free (TYPE_OBSTACK (type), type);
+      if (!ggc_p)
+       obstack_free (TYPE_OBSTACK (type), type);
+
 #ifdef GATHER_STATISTICS
-      tree_node_counts[(int)t_kind]--;
-      tree_node_sizes[(int)t_kind] -= sizeof (struct tree_type);
+      tree_node_counts[(int) t_kind]--;
+      tree_node_sizes[(int) t_kind] -= sizeof (struct tree_type);
 #endif
       return t1;
     }
 
   /* If this is a permanent type, record it for later reuse.  */
-  if (TREE_PERMANENT (type))
+  if (ggc_p || TREE_PERMANENT (type))
     type_hash_add (hashcode, type);
 
   return type;
 }
 
+/* Callback function for htab_traverse.  */
+
+static int
+mark_hash_entry (entry, param)
+     void **entry;
+     void *param ATTRIBUTE_UNUSED;
+{
+  struct type_hash *p = *(struct type_hash **)entry;
+
+  ggc_mark_tree (p->type);
+
+  /* Continue scan.  */
+  return 1;
+}
+
+/* Mark ARG (which is really a htab_t *) for GC.  */
+
+static void
+mark_type_hash (arg)
+     void *arg;
+{
+  htab_t t = *(htab_t *) arg;
+
+  htab_traverse (t, mark_hash_entry, 0);
+}
+
+static void
+print_type_hash_statistics ()
+{
+  fprintf (stderr, "Type hash: size %ld, %ld elements, %f collisions\n",
+          (long) htab_size (type_hash_table),
+          (long) htab_elements (type_hash_table),
+          htab_collisions (type_hash_table));
+}
+
 /* Compute a hash code for a list of attributes (chain of TREE_LIST nodes
    with names in the TREE_PURPOSE slots and args in the TREE_VALUE slots),
    by adding the hash codes of the individual attributes.  */
 
-int
+unsigned int
 attribute_hash_list (list)
      tree list;
 {
-  register int hashcode;
+  unsigned int hashcode;
   register tree tail;
+
   for (hashcode = 0, tail = list; tail; tail = TREE_CHAIN (tail))
     /* ??? Do we want to add in TREE_VALUE too? */
     hashcode += TYPE_HASH (TREE_PURPOSE (tail));
@@ -3837,7 +4208,7 @@ attribute_list_contained (l1, l2)
 
   /* Maybe the lists are similar.  */
   for (t1 = l1, t2 = l2;
-       t1 && t2
+       t1 != 0 && t2 != 0
         && TREE_PURPOSE (t1) == TREE_PURPOSE (t2)
         && TREE_VALUE (t1) == TREE_VALUE (t2);
        t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2));
@@ -3846,13 +4217,14 @@ attribute_list_contained (l1, l2)
   if (t1 == 0 && t2 == 0)
      return 1;
 
-  for (; t2; t2 = TREE_CHAIN (t2))
+  for (; t2 != 0; t2 = TREE_CHAIN (t2))
     {
       tree attr
        = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (t2)), l1);
 
-      if (attr == NULL_TREE)
+      if (attr == 0)
        return 0;
+
       if (simple_cst_equal (TREE_VALUE (t2), TREE_VALUE (attr)) != 1)
        return 0;
     }
@@ -3891,13 +4263,16 @@ tree_int_cst_equal (t1, t2)
 {
   if (t1 == t2)
     return 1;
+
   if (t1 == 0 || t2 == 0)
     return 0;
+
   if (TREE_CODE (t1) == INTEGER_CST
       && TREE_CODE (t2) == INTEGER_CST
       && TREE_INT_CST_LOW (t1) == TREE_INT_CST_LOW (t2)
       && TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2))
     return 1;
+
   return 0;
 }
 
@@ -3911,11 +4286,63 @@ tree_int_cst_lt (t1, t2)
   if (t1 == t2)
     return 0;
 
-  if (!TREE_UNSIGNED (TREE_TYPE (t1)))
+  if (! TREE_UNSIGNED (TREE_TYPE (t1)))
     return INT_CST_LT (t1, t2);
+
   return INT_CST_LT_UNSIGNED (t1, t2);
 }
 
+/* Return 1 if T is an INTEGER_CST that can be represented in a single
+   HOST_WIDE_INT value.  If POS is nonzero, the result must be positive.  */
+
+int
+host_integerp (t, pos)
+     tree t;
+     int pos;
+{
+  return (TREE_CODE (t) == INTEGER_CST
+         && ! TREE_OVERFLOW (t)
+         && ((TREE_INT_CST_HIGH (t) == 0
+              && (HOST_WIDE_INT) TREE_INT_CST_LOW (t) >= 0)
+             || (! pos && TREE_INT_CST_HIGH (t) == -1
+                 && (HOST_WIDE_INT) TREE_INT_CST_LOW (t) < 0)
+             || (! pos && TREE_INT_CST_HIGH (t) == 0
+                 && TREE_UNSIGNED (TREE_TYPE (t)))));
+}
+
+/* Return the HOST_WIDE_INT least significant bits of T if it is an
+   INTEGER_CST and there is no overflow.  POS is nonzero if the result must
+   be positive.  Abort if we cannot satisfy the above conditions.  */
+
+HOST_WIDE_INT
+tree_low_cst (t, pos)
+     tree t;
+     int pos;
+{
+  if (host_integerp (t, pos))
+    return TREE_INT_CST_LOW (t);
+  else
+    abort ();
+}  
+
+/* Return the most significant bit of the integer constant T.  */
+
+int
+tree_int_cst_msb (t)
+     tree t;
+{
+  register int prec;
+  HOST_WIDE_INT h;
+  unsigned HOST_WIDE_INT l;
+
+  /* Note that using TYPE_PRECISION here is wrong.  We care about the
+     actual bits, not the (arbitrary) range of the type.  */
+  prec = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (t))) - 1;
+  rshift_double (TREE_INT_CST_LOW (t), TREE_INT_CST_HIGH (t), prec,
+                2 * HOST_BITS_PER_WIDE_INT, &l, &h, 0);
+  return (l & 1) == 1;
+  }
+
 /* Return an indication of the sign of the integer constant T.
    The return value is -1 if T < 0, 0 if T == 0, and 1 if T > 0.
    Note that -1 will never be returned it T's type is unsigned.  */
@@ -3934,6 +4361,25 @@ tree_int_cst_sgn (t)
     return 1;
 }
 
+/* Return true if `t' is known to be non-negative.  */
+
+int
+tree_expr_nonnegative_p (t)
+     tree t;
+{
+  switch (TREE_CODE (t))
+    {
+    case INTEGER_CST:
+      return tree_int_cst_sgn (t) >= 0;
+    case COND_EXPR:
+      return tree_expr_nonnegative_p (TREE_OPERAND (t, 1))
+       && tree_expr_nonnegative_p (TREE_OPERAND (t, 2));
+    default:
+      /* We don't know sign of `t', so be safe and return false.  */
+      return 0;
+    }
+}
+
 /* Compare two constructor-element-type constants.  Return 1 if the lists
    are known to be equal; otherwise return 0.  */
 
@@ -3950,7 +4396,7 @@ simple_cst_list_equal (l1, l2)
       l2 = TREE_CHAIN (l2);
     }
 
-  return (l1 == l2);
+  return l1 == l2;
 }
 
 /* Return truthvalue of whether T1 is the same tree structure as T2.
@@ -3965,6 +4411,7 @@ simple_cst_equal (t1, t2)
 {
   register enum tree_code code1, code2;
   int cmp;
+  int i;
 
   if (t1 == t2)
     return 1;
@@ -3982,6 +4429,7 @@ simple_cst_equal (t1, t2)
       else
        return simple_cst_equal (TREE_OPERAND (t1, 0), t2);
     }
+
   else if (code2 == NOP_EXPR || code2 == CONVERT_EXPR
           || code2 == NON_LVALUE_EXPR)
     return simple_cst_equal (t1, TREE_OPERAND (t2, 0));
@@ -3992,16 +4440,16 @@ simple_cst_equal (t1, t2)
   switch (code1)
     {
     case INTEGER_CST:
-      return TREE_INT_CST_LOW (t1) == TREE_INT_CST_LOW (t2)
-       && TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2);
+      return (TREE_INT_CST_LOW (t1) == TREE_INT_CST_LOW (t2)
+             && TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2));
 
     case REAL_CST:
       return REAL_VALUES_IDENTICAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2));
 
     case STRING_CST:
-      return TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2)
-       && !bcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
-                 TREE_STRING_LENGTH (t1));
+      return (TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2)
+             && ! bcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
+                        TREE_STRING_LENGTH (t1)));
 
     case CONSTRUCTOR:
       if (CONSTRUCTOR_ELTS (t1) == CONSTRUCTOR_ELTS (t2))
@@ -4016,7 +4464,8 @@ simple_cst_equal (t1, t2)
       cmp = simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
       if (cmp <= 0)
        return cmp;
-      return simple_cst_list_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
+      return
+       simple_cst_list_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
 
     case TARGET_EXPR:
       /* Special case: if either target is an unallocated VAR_DECL,
@@ -4032,19 +4481,23 @@ simple_cst_equal (t1, t2)
        cmp = 1;
       else
        cmp = simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+
       if (cmp <= 0)
        return cmp;
+
       return simple_cst_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
 
     case WITH_CLEANUP_EXPR:
       cmp = simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
       if (cmp <= 0)
        return cmp;
+
       return simple_cst_equal (TREE_OPERAND (t1, 2), TREE_OPERAND (t1, 2));
 
     case COMPONENT_REF:
       if (TREE_OPERAND (t1, 1) == TREE_OPERAND (t2, 1))
        return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+
       return 0;
 
     case VAR_DECL:
@@ -4066,7 +4519,6 @@ simple_cst_equal (t1, t2)
 
   switch (TREE_CODE_CLASS (code1))
     {
-      int i;
     case '1':
     case '2':
     case '<':
@@ -4074,18 +4526,40 @@ simple_cst_equal (t1, t2)
     case 'r':
     case 's':
       cmp = 1;
-      for (i=0; i<tree_code_length[(int) code1]; ++i)
+      for (i = 0; i < TREE_CODE_LENGTH (code1); i++)
        {
          cmp = simple_cst_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i));
          if (cmp <= 0)
            return cmp;
        }
+
       return cmp;
 
     default:
       return -1;
     }
 }
+
+/* Compare the value of T, an INTEGER_CST, with U, an unsigned integer value.
+   Return -1, 0, or 1 if the value of T is less than, equal to, or greater
+   than U, respectively.  */
+
+int
+compare_tree_int (t, u)
+     tree t;
+     unsigned int u;
+{
+  if (tree_int_cst_sgn (t) < 0)
+    return -1;
+  else if (TREE_INT_CST_HIGH (t) != 0)
+    return 1;
+  else if (TREE_INT_CST_LOW (t) == u)
+    return 0;
+  else if (TREE_INT_CST_LOW (t) < u)
+    return -1;
+  else
+    return 1;
+}
 \f
 /* Constructors for pointer, array and function types.
    (RECORD_TYPE, UNION_TYPE and ENUMERAL_TYPE nodes are
@@ -4102,7 +4576,7 @@ build_pointer_type (to_type)
 
   /* First, if we already have a type for pointers to TO_TYPE, use it.  */
 
-  if (t)
+  if (t != 0)
     return t;
 
   /* We need a new one.  Put this in the same obstack as TO_TYPE.   */
@@ -4123,6 +4597,34 @@ build_pointer_type (to_type)
   return t;
 }
 
+/* Build the node for the type of references-to-TO_TYPE.  */
+
+tree
+build_reference_type (to_type)
+     tree to_type;
+{
+  register tree t = TYPE_REFERENCE_TO (to_type);
+
+  /* First, if we already have a type for pointers to TO_TYPE, use it.  */
+
+  if (t)
+    return t;
+
+  /* We need a new one.  Put this in the same obstack as TO_TYPE.   */
+  push_obstacks (TYPE_OBSTACK (to_type), TYPE_OBSTACK (to_type));
+  t = make_node (REFERENCE_TYPE);
+  pop_obstacks ();
+
+  TREE_TYPE (t) = to_type;
+
+  /* Record this type as the pointer to TO_TYPE.  */
+  TYPE_REFERENCE_TO (to_type) = t;
+
+  layout_type (t);
+
+  return t;
+}
+
 /* Create a type of integers to be the TYPE_DOMAIN of an ARRAY_TYPE.
    MAXVAL should be the maximum value in the domain
    (one less than the length of the array).
@@ -4138,6 +4640,7 @@ build_index_type (maxval)
 {
   register tree itype = make_node (INTEGER_TYPE);
 
+  TREE_TYPE (itype) = sizetype;
   TYPE_PRECISION (itype) = TYPE_PRECISION (sizetype);
   TYPE_MIN_VALUE (itype) = size_zero_node;
 
@@ -4149,18 +4652,10 @@ build_index_type (maxval)
   TYPE_SIZE (itype) = TYPE_SIZE (sizetype);
   TYPE_SIZE_UNIT (itype) = TYPE_SIZE_UNIT (sizetype);
   TYPE_ALIGN (itype) = TYPE_ALIGN (sizetype);
-  if (TREE_CODE (maxval) == INTEGER_CST)
-    {
-      int maxint = (int) TREE_INT_CST_LOW (maxval);
-      /* If the domain should be empty, make sure the maxval
-        remains -1 and is not spoiled by truncation.  */
-      if (INT_CST_LT (maxval, integer_zero_node))
-       {
-         TYPE_MAX_VALUE (itype) = build_int_2 (-1, -1);
-         TREE_TYPE (TYPE_MAX_VALUE (itype)) = sizetype;
-       }
-      return type_hash_canon (maxint < 0 ? ~maxint : maxint, itype);
-    }
+  TYPE_USER_ALIGN (itype) = TYPE_USER_ALIGN (sizetype);
+
+  if (host_integerp (maxval, 1))
+    return type_hash_canon (tree_low_cst (maxval, 1), itype);
   else
     return itype;
 }
@@ -4190,20 +4685,12 @@ build_range_type (type, lowval, highval)
   TYPE_SIZE (itype) = TYPE_SIZE (type);
   TYPE_SIZE_UNIT (itype) = TYPE_SIZE_UNIT (type);
   TYPE_ALIGN (itype) = TYPE_ALIGN (type);
-  if (TREE_CODE (lowval) == INTEGER_CST)
-    {
-      HOST_WIDE_INT lowint, highint;
-      int maxint;
-
-      lowint = TREE_INT_CST_LOW (lowval);
-      if (highval && TREE_CODE (highval) == INTEGER_CST)
-       highint = TREE_INT_CST_LOW (highval);
-      else
-       highint = (~(unsigned HOST_WIDE_INT)0) >> 1;
+  TYPE_USER_ALIGN (itype) = TYPE_USER_ALIGN (type);
 
-      maxint = (int) (highint - lowint);
-      return type_hash_canon (maxint < 0 ? ~maxint : maxint, itype);
-    }
+  if (host_integerp (lowval, 0) && highval != 0 && host_integerp (highval, 0))
+    return type_hash_canon (tree_low_cst (highval, 0)
+                           - tree_low_cst (lowval, 0),
+                           itype);
   else
     return itype;
 }
@@ -4215,7 +4702,7 @@ tree
 build_index_2_type (lowval,highval)
      tree lowval, highval;
 {
-  return build_range_type (NULL_TREE, lowval, highval);
+  return build_range_type (sizetype, lowval, highval);
 }
 
 /* Return nonzero iff ITYPE1 and ITYPE2 are equal (in the LISP sense).
@@ -4229,6 +4716,7 @@ index_type_equal (itype1, itype2)
 {
   if (TREE_CODE (itype1) != TREE_CODE (itype2))
     return 0;
+
   if (TREE_CODE (itype1) == INTEGER_TYPE)
     {
       if (TYPE_PRECISION (itype1) != TYPE_PRECISION (itype2)
@@ -4236,6 +4724,7 @@ index_type_equal (itype1, itype2)
          || simple_cst_equal (TYPE_SIZE (itype1), TYPE_SIZE (itype2)) != 1
          || TYPE_ALIGN (itype1) != TYPE_ALIGN (itype2))
        return 0;
+
       if (1 == simple_cst_equal (TYPE_MIN_VALUE (itype1),
                                 TYPE_MIN_VALUE (itype2))
          && 1 == simple_cst_equal (TYPE_MAX_VALUE (itype1),
@@ -4255,7 +4744,7 @@ build_array_type (elt_type, index_type)
      tree elt_type, index_type;
 {
   register tree t;
-  int hashcode;
+  unsigned int hashcode;
 
   if (TREE_CODE (elt_type) == FUNCTION_TYPE)
     {
@@ -4280,7 +4769,7 @@ build_array_type (elt_type, index_type)
   hashcode = TYPE_HASH (elt_type) + TYPE_HASH (index_type);
   t = type_hash_canon (hashcode, t);
 
-  if (TYPE_SIZE (t) == 0)
+  if (!COMPLETE_TYPE_P (t))
     layout_type (t);
   return t;
 }
@@ -4312,7 +4801,7 @@ build_function_type (value_type, arg_types)
      tree value_type, arg_types;
 {
   register tree t;
-  int hashcode;
+  unsigned int hashcode;
 
   if (TREE_CODE (value_type) == FUNCTION_TYPE)
     {
@@ -4329,39 +4818,11 @@ build_function_type (value_type, arg_types)
   hashcode = TYPE_HASH (value_type) + type_hash_list (arg_types);
   t = type_hash_canon (hashcode, t);
 
-  if (TYPE_SIZE (t) == 0)
+  if (!COMPLETE_TYPE_P (t))
     layout_type (t);
   return t;
 }
 
-/* Build the node for the type of references-to-TO_TYPE.  */
-
-tree
-build_reference_type (to_type)
-     tree to_type;
-{
-  register tree t = TYPE_REFERENCE_TO (to_type);
-
-  /* First, if we already have a type for pointers to TO_TYPE, use it.  */
-
-  if (t)
-    return t;
-
-  /* We need a new one.  Put this in the same obstack as TO_TYPE.   */
-  push_obstacks (TYPE_OBSTACK (to_type), TYPE_OBSTACK (to_type));
-  t = make_node (REFERENCE_TYPE);
-  pop_obstacks ();
-
-  TREE_TYPE (t) = to_type;
-
-  /* Record this type as the pointer to TO_TYPE.  */
-  TYPE_REFERENCE_TO (to_type) = t;
-
-  layout_type (t);
-
-  return t;
-}
-
 /* Construct, lay out and return the type of methods belonging to class
    BASETYPE and whose arguments and values are described by TYPE.
    If that type exists already, reuse it.
@@ -4372,7 +4833,7 @@ build_method_type (basetype, type)
      tree basetype, type;
 {
   register tree t;
-  int hashcode;
+  unsigned int hashcode;
 
   /* Make a node of the sort we want.  */
   t = make_node (METHOD_TYPE);
@@ -4394,7 +4855,7 @@ build_method_type (basetype, type)
   hashcode = TYPE_HASH (basetype) + TYPE_HASH (type);
   t = type_hash_canon (hashcode, t);
 
-  if (TYPE_SIZE (t) == 0)
+  if (!COMPLETE_TYPE_P (t))
     layout_type (t);
 
   return t;
@@ -4409,7 +4870,7 @@ build_offset_type (basetype, type)
      tree basetype, type;
 {
   register tree t;
-  int hashcode;
+  unsigned int hashcode;
 
   /* Make a node of the sort we want.  */
   t = make_node (OFFSET_TYPE);
@@ -4421,7 +4882,7 @@ build_offset_type (basetype, type)
   hashcode = TYPE_HASH (basetype) + TYPE_HASH (type);
   t = type_hash_canon (hashcode, t);
 
-  if (TYPE_SIZE (t) == 0)
+  if (!COMPLETE_TYPE_P (t))
     layout_type (t);
 
   return t;
@@ -4434,7 +4895,7 @@ build_complex_type (component_type)
      tree component_type;
 {
   register tree t;
-  int hashcode;
+  unsigned int hashcode;
 
   /* Make a node of the sort we want.  */
   t = make_node (COMPLEX_TYPE);
@@ -4446,9 +4907,43 @@ build_complex_type (component_type)
   hashcode = TYPE_HASH (component_type);
   t = type_hash_canon (hashcode, t);
 
-  if (TYPE_SIZE (t) == 0)
+  if (!COMPLETE_TYPE_P (t))
     layout_type (t);
 
+  /* If we are writing Dwarf2 output we need to create a name,
+     since complex is a fundamental type.  */
+  if (write_symbols == DWARF2_DEBUG && ! TYPE_NAME (t))
+    {
+      const char *name;
+      if (component_type == char_type_node)
+       name = "complex char";
+      else if (component_type == signed_char_type_node)
+       name = "complex signed char";
+      else if (component_type == unsigned_char_type_node)
+       name = "complex unsigned char";
+      else if (component_type == short_integer_type_node)
+       name = "complex short int";
+      else if (component_type == short_unsigned_type_node)
+       name = "complex short unsigned int";
+      else if (component_type == integer_type_node)
+       name = "complex int";
+      else if (component_type == unsigned_type_node)
+       name = "complex unsigned int";
+      else if (component_type == long_integer_type_node)
+       name = "complex long int";
+      else if (component_type == long_unsigned_type_node)
+       name = "complex long unsigned int";
+      else if (component_type == long_long_integer_type_node)
+       name = "complex long long int";
+      else if (component_type == long_long_unsigned_type_node)
+       name = "complex long long unsigned int";
+      else
+       name = 0;
+
+      if (name != 0)
+       TYPE_NAME (t) = get_identifier (name);
+    }
+
   return t;
 }
 \f
@@ -4535,7 +5030,9 @@ get_unwidened (op, for_type)
       /* Don't crash if field not laid out yet.  */
       && DECL_SIZE (TREE_OPERAND (op, 1)) != 0)
     {
-      unsigned innerprec = TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (op, 1)));
+      unsigned int innerprec
+       = TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (op, 1)));
+
       type = type_for_size (innerprec, TREE_UNSIGNED (TREE_OPERAND (op, 1)));
 
       /* We can get this structure field in the narrowest type it fits in.
@@ -4554,7 +5051,6 @@ get_unwidened (op, for_type)
                       TREE_OPERAND (op, 1));
          TREE_SIDE_EFFECTS (win) = TREE_SIDE_EFFECTS (op);
          TREE_THIS_VOLATILE (win) = TREE_THIS_VOLATILE (op);
-         TREE_RAISES (win) = TREE_RAISES (op);
        }
     }
   return win;
@@ -4577,8 +5073,8 @@ get_narrower (op, unsignedp_ptr)
   while (TREE_CODE (op) == NOP_EXPR)
     {
       register int bitschange
-       = TYPE_PRECISION (TREE_TYPE (op))
-         - TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op, 0)));
+       = (TYPE_PRECISION (TREE_TYPE (op))
+          - TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op, 0))));
 
       /* Truncations are many-one so cannot be removed.  */
       if (bitschange < 0)
@@ -4617,7 +5113,9 @@ get_narrower (op, unsignedp_ptr)
       /* Since type_for_size always gives an integer type.  */
       && TREE_CODE (TREE_TYPE (op)) != REAL_TYPE)
     {
-      unsigned innerprec = TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (op, 1)));
+      unsigned int innerprec
+       = TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (op, 1)));
+
       tree type = type_for_size (innerprec, TREE_UNSIGNED (op));
 
       /* We can get this structure field in a narrower type that fits it,
@@ -4639,7 +5137,6 @@ get_narrower (op, unsignedp_ptr)
                       TREE_OPERAND (op, 1));
          TREE_SIDE_EFFECTS (win) = TREE_SIDE_EFFECTS (op);
          TREE_THIS_VOLATILE (win) = TREE_THIS_VOLATILE (op);
-         TREE_RAISES (win) = TREE_RAISES (op);
        }
     }
   *unsignedp_ptr = uns;
@@ -4671,6 +5168,16 @@ int_fits_type_p (c, type)
                  && TREE_UNSIGNED (TREE_TYPE (c))));
 }
 
+/* Given a DECL or TYPE, return the scope in which it was declared, or
+   NULL_TREE if there is no containing scope.  */
+
+tree
+get_containing_scope (t)
+     tree t;
+{
+  return (TYPE_P (t) ? TYPE_CONTEXT (t) : DECL_CONTEXT (t));
+}
+
 /* Return the innermost context enclosing DECL that is
    a FUNCTION_DECL, or zero if none.  */
 
@@ -4685,20 +5192,26 @@ decl_function_context (decl)
 
   if (TREE_CODE (decl) == SAVE_EXPR)
     context = SAVE_EXPR_CONTEXT (decl);
+
+  /* C++ virtual functions use DECL_CONTEXT for the class of the vtable
+     where we look up the function at runtime.  Such functions always take
+     a first argument of type 'pointer to real context'.
+
+     C++ should really be fixed to use DECL_CONTEXT for the real context,
+     and use something else for the "virtual context".  */
+  else if (TREE_CODE (decl) == FUNCTION_DECL && DECL_VINDEX (decl))
+    context
+      = TYPE_MAIN_VARIANT
+       (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)))));
   else
     context = DECL_CONTEXT (decl);
 
   while (context && TREE_CODE (context) != FUNCTION_DECL)
     {
-      if (TREE_CODE_CLASS (TREE_CODE (context)) == 't')
-       context = TYPE_CONTEXT (context);
-      else if (TREE_CODE_CLASS (TREE_CODE (context)) == 'd')
-       context = DECL_CONTEXT (context);
-      else if (TREE_CODE (context) == BLOCK)
+      if (TREE_CODE (context) == BLOCK)
        context = BLOCK_SUPERCONTEXT (context);
-      else
-       /* Unhandled CONTEXT !?  */
-       abort ();
+      else 
+       context = get_containing_scope (context);
     }
 
   return context;
@@ -4720,11 +5233,14 @@ decl_type_context (decl)
          || TREE_CODE (context) == UNION_TYPE
          || TREE_CODE (context) == QUAL_UNION_TYPE)
        return context;
+
       if (TREE_CODE (context) == TYPE_DECL
          || TREE_CODE (context) == FUNCTION_DECL)
        context = DECL_CONTEXT (context);
+
       else if (TREE_CODE (context) == BLOCK)
        context = BLOCK_SUPERCONTEXT (context);
+
       else
        /* Unhandled CONTEXT!?  */
        abort ();
@@ -4732,30 +5248,41 @@ decl_type_context (decl)
   return NULL_TREE;
 }
 
-/* Print debugging information about the size of the
-   toplev_inline_obstacks.  */
+/* CALL is a CALL_EXPR.  Return the declaration for the function
+   called, or NULL_TREE if the called function cannot be 
+   determined.  */
 
-void
-print_inline_obstack_statistics ()
+tree
+get_callee_fndecl (call)
+     tree call;
 {
-  struct simple_obstack_stack *current = toplev_inline_obstacks;
-  int n_obstacks = 0;
-  int n_alloc = 0;
-  int n_chunks = 0;
+  tree addr;
 
-  for (; current; current = current->next, ++n_obstacks)
-    {
-      struct obstack *o = current->obstack;
-      struct _obstack_chunk *chunk = o->chunk;
+  /* It's invalid to call this function with anything but a
+     CALL_EXPR.  */
+  if (TREE_CODE (call) != CALL_EXPR)
+    abort ();
 
-      n_alloc += o->next_free - chunk->contents;
-      chunk = chunk->prev;
-      ++n_chunks;
-      for (; chunk; chunk = chunk->prev, ++n_chunks)
-       n_alloc += chunk->limit - &chunk->contents[0];
-    }
-  fprintf (stderr, "inline obstacks: %d obstacks, %d bytes, %d chunks\n",
-          n_obstacks, n_alloc, n_chunks);
+  /* The first operand to the CALL is the address of the function
+     called.  */
+  addr = TREE_OPERAND (call, 0);
+
+  STRIP_NOPS (addr);
+
+  /* If this is a readonly function pointer, extract its initial value.  */
+  if (DECL_P (addr) && TREE_CODE (addr) != FUNCTION_DECL
+      && TREE_READONLY (addr) && ! TREE_THIS_VOLATILE (addr)
+      && DECL_INITIAL (addr))
+    addr = DECL_INITIAL (addr);
+
+  /* If the address is just `&f' for some function `f', then we know
+     that `f' is being called.  */
+  if (TREE_CODE (addr) == ADDR_EXPR
+      && TREE_CODE (TREE_OPERAND (addr, 0)) == FUNCTION_DECL)
+    return TREE_OPERAND (addr, 0);
+
+  /* We couldn't figure out what was being called.  */
+  return NULL_TREE;
 }
 
 /* Print debugging information about the obstack O, named STR.  */
@@ -4816,7 +5343,7 @@ dump_tree_statistics ()
   print_obstack_statistics ("temporary_obstack", &temporary_obstack);
   print_obstack_statistics ("momentary_obstack", &momentary_obstack);
   print_obstack_statistics ("temp_decl_obstack", &temp_decl_obstack);
-  print_inline_obstack_statistics ();
+  print_type_hash_statistics ();
   print_lang_statistics ();
 }
 \f
@@ -4832,9 +5359,6 @@ dump_tree_statistics ()
 #endif /* NO_DOT_IN_LABEL */
 #endif /* NO_DOLLAR_IN_LABEL */
 
-extern char * first_global_object_name;
-extern char * weak_global_object_name;
-
 /* Appends 6 random characters to TEMPLATE to (hopefully) avoid name
    clashes in cases where we can't reliably choose a unique name.
 
@@ -4890,7 +5414,8 @@ get_file_function_name_long (type)
      const char *type;
 {
   char *buf;
-  register char *p;
+  const char *p;
+  char *q;
 
   if (first_global_object_name)
     p = first_global_object_name;
@@ -4907,40 +5432,36 @@ get_file_function_name_long (type)
       if (! file)
        file = input_filename;
 
-      p = (char *) alloca (7 + strlen (name) + strlen (file));
+      q = (char *) alloca (7 + strlen (name) + strlen (file));
 
-      sprintf (p, "%s%s", name, file);
-      append_random_chars (p);
+      sprintf (q, "%s%s", name, file);
+      append_random_chars (q);
+      p = q;
     }
 
   buf = (char *) alloca (sizeof (FILE_FUNCTION_FORMAT) + strlen (p)
                         + strlen (type));
 
-  /* Set up the name of the file-level functions we may need.  */
-  /* Use a global object (which is already required to be unique over
+  /* Set up the name of the file-level functions we may need. 
+     Use a global object (which is already required to be unique over
      the program) rather than the file name (which imposes extra
-     constraints).  -- Raeburn@MIT.EDU, 10 Jan 1990.  */
+     constraints).  */
   sprintf (buf, FILE_FUNCTION_FORMAT, type, p);
 
   /* Don't need to pull weird characters out of global names.  */
   if (p != first_global_object_name)
     {
-      for (p = buf+11; *p; p++)
-       if (! ((*p >= '0' && *p <= '9')
-#if 0 /* we always want labels, which are valid C++ identifiers (+ `$') */
-#ifndef ASM_IDENTIFY_GCC       /* this is required if `.' is invalid -- k. raeburn */
-              || *p == '.'
-#endif
-#endif
+      for (q = buf+11; *q; q++)
+       if (! ( ISDIGIT(*q)
 #ifndef NO_DOLLAR_IN_LABEL     /* this for `$'; unlikely, but... -- kr */
-              || *p == '$'
+              || *q == '$'
 #endif
 #ifndef NO_DOT_IN_LABEL                /* this for `.'; unlikely, but...  */
-              || *p == '.'
+              || *q == '.'
 #endif
-              || (*p >= 'A' && *p <= 'Z')
-              || (*p >= 'a' && *p <= 'z')))
-         *p = '_';
+              || ISUPPER(*q)
+              || ISLOWER(*q)))
+         *q = '_';
     }
 
   return get_identifier (buf);
@@ -4954,12 +5475,12 @@ get_file_function_name (kind)
      int kind;
 {
   char p[2];
+
   p[0] = kind;
   p[1] = 0;
 
   return get_file_function_name_long (p);
 }
-
 \f
 /* Expand (the constant part of) a SET_TYPE CONSTRUCTOR node.
    The result is placed in BUFFER (which has length BIT_SIZE),
@@ -4997,6 +5518,7 @@ get_set_constructor_bits (init, buffer, bit_size)
            = TREE_INT_CST_LOW (TREE_PURPOSE (vals)) - domain_min;
          HOST_WIDE_INT hi_index
            = TREE_INT_CST_LOW (TREE_VALUE (vals)) - domain_min;
+
          if (lo_index < 0 || lo_index >= bit_size
            || hi_index < 0 || hi_index >= bit_size)
            abort ();
@@ -5057,107 +5579,241 @@ get_set_constructor_bytes (init, buffer, wd_size)
   return non_const_bits;
 }
 \f
-#ifdef ENABLE_CHECKING
-
-/* Complain if the tree code does not match the expected one.
-   NODE is the tree node in question, CODE is the expected tree code,
-   and FILE and LINE are the filename and line number, respectively,
-   of the line on which the check was done.  If NONFATAL is nonzero,
-   don't abort if the reference is invalid; instead, return 0.
-   If the reference is valid, return NODE.  */
-
-tree
-tree_check (node, code, file, line, nofatal)
-     tree node;
+#if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007)
+/* Complain that the tree code of NODE does not match the expected CODE.
+   FILE, LINE, and FUNCTION are of the caller.  */
+void
+tree_check_failed (node, code, file, line, function)
+     const tree node;
      enum tree_code code;
      const char *file;
      int line;
-     int nofatal;
+     const char *function;
 {
-  if (TREE_CODE (node) == code)
-    return node;
-  else if (nofatal)
-    return 0;
-  else
-    fatal ("%s:%d: Expect %s, have %s\n", file, line,
-          tree_code_name[code], tree_code_name[TREE_CODE (node)]);
+  error ("Tree check: expected %s, have %s",
+        tree_code_name[code], tree_code_name[TREE_CODE (node)]);
+  fancy_abort (file, line, function);
 }
 
 /* Similar to above, except that we check for a class of tree
    code, given in CL.  */
-
-tree
-tree_class_check (node, cl, file, line, nofatal)
-     tree node;
-     char cl;
+void
+tree_class_check_failed (node, cl, file, line, function)
+     const tree node;
+     int cl;
      const char *file;
      int line;
-     int nofatal;
+     const char *function;
 {
-  if (TREE_CODE_CLASS (TREE_CODE (node)) == cl)
-    return node;
-  else if (nofatal)
-    return 0;
-  else
-    fatal ("%s:%d: Expect '%c', have '%s'\n", file, line,
-          cl, tree_code_name[TREE_CODE (node)]);
+  error ("Tree check: expected class '%c', have '%c' (%s)",
+        cl, TREE_CODE_CLASS (TREE_CODE (node)),
+        tree_code_name[TREE_CODE (node)]);
+  fancy_abort (file, line, function);
 }
 
-/* Likewise, but complain if the tree node is not an expression.  */
+#endif /* ENABLE_TREE_CHECKING */
 
-tree
-expr_check (node, ignored, file, line, nofatal)
-     tree node;
-     int ignored;
-     const char *file;
-     int line;
-     int nofatal;
+\f
+/* For a new vector type node T, build the information necessary for
+   debuggint output.  */
+static void
+finish_vector_type (t)
+     tree t;
 {
-  switch (TREE_CODE_CLASS (TREE_CODE (node)))
-    {
-    case 'r':
-    case 's':
-    case 'e':
-    case '<':
-    case '1':
-    case '2':
-      break;
-
-    default:
-      if (nofatal)
-       return 0;
-      else
-       fatal ("%s:%d: Expect expression, have '%s'\n", file, line,
-              tree_code_name[TREE_CODE (node)]);
-    }
+  layout_type (t);
 
-  return node;
+  {
+    tree index = build_int_2 (TYPE_VECTOR_SUBPARTS (t) - 1, 0);
+    tree array = build_array_type (TREE_TYPE (t),
+                                  build_index_type (index));
+    tree rt = make_node (RECORD_TYPE);
+
+    TYPE_FIELDS (rt) = build_decl (FIELD_DECL, get_identifier ("f"), array);
+    DECL_CONTEXT (TYPE_FIELDS (rt)) = rt;
+    layout_type (rt);
+    TYPE_DEBUG_REPRESENTATION_TYPE (t) = rt;
+    /* In dwarfout.c, type lookup uses TYPE_UID numbers.  We want to output
+       the representation type, and we want to find that die when looking up
+       the vector type.  This is most easily achieved by making the TYPE_UID
+       numbers equal.  */
+    TYPE_UID (rt) = TYPE_UID (t);
+  }
 }
+
+#ifndef CHAR_TYPE_SIZE
+#define CHAR_TYPE_SIZE BITS_PER_UNIT
 #endif
 
-/* Return the alias set for T, which may be either a type or an
-   expression.  */
+#ifndef SHORT_TYPE_SIZE
+#define SHORT_TYPE_SIZE (BITS_PER_UNIT * MIN ((UNITS_PER_WORD + 1) / 2, 2))
+#endif
 
-int
-get_alias_set (t)
-     tree t;
-{
-  if (!flag_strict_aliasing || !lang_get_alias_set)
-    /* If we're not doing any lanaguage-specific alias analysis, just
-       assume everything aliases everything else.  */
-    return 0;
-  else
-    return (*lang_get_alias_set) (t);
+#ifndef INT_TYPE_SIZE
+#define INT_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef LONG_TYPE_SIZE
+#define LONG_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef LONG_LONG_TYPE_SIZE
+#define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+#ifndef FLOAT_TYPE_SIZE
+#define FLOAT_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef DOUBLE_TYPE_SIZE
+#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+#ifndef LONG_DOUBLE_TYPE_SIZE
+#define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+/* Create nodes for all integer types (and error_mark_node) using the sizes
+   of C datatypes.  The caller should call set_sizetype soon after calling
+   this function to select one of the types as sizetype.  */
+   
+void
+build_common_tree_nodes (signed_char)
+     int signed_char;
+{
+  error_mark_node = make_node (ERROR_MARK);
+  TREE_TYPE (error_mark_node) = error_mark_node;
+
+  initialize_sizetypes ();
+
+  /* Define both `signed char' and `unsigned char'.  */
+  signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE);
+  unsigned_char_type_node = make_unsigned_type (CHAR_TYPE_SIZE);
+
+  /* Define `char', which is like either `signed char' or `unsigned char'
+     but not the same as either.  */
+  char_type_node
+    = (signed_char
+       ? make_signed_type (CHAR_TYPE_SIZE)
+       : make_unsigned_type (CHAR_TYPE_SIZE));
+
+  short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE);
+  short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE);
+  integer_type_node = make_signed_type (INT_TYPE_SIZE);
+  unsigned_type_node = make_unsigned_type (INT_TYPE_SIZE);
+  long_integer_type_node = make_signed_type (LONG_TYPE_SIZE);
+  long_unsigned_type_node = make_unsigned_type (LONG_TYPE_SIZE);
+  long_long_integer_type_node = make_signed_type (LONG_LONG_TYPE_SIZE);
+  long_long_unsigned_type_node = make_unsigned_type (LONG_LONG_TYPE_SIZE);
+
+  intQI_type_node = make_signed_type (GET_MODE_BITSIZE (QImode));
+  intHI_type_node = make_signed_type (GET_MODE_BITSIZE (HImode));
+  intSI_type_node = make_signed_type (GET_MODE_BITSIZE (SImode));
+  intDI_type_node = make_signed_type (GET_MODE_BITSIZE (DImode));
+#if HOST_BITS_PER_WIDE_INT >= 64
+  intTI_type_node = make_signed_type (GET_MODE_BITSIZE (TImode));
+#endif
+
+  unsigned_intQI_type_node = make_unsigned_type (GET_MODE_BITSIZE (QImode));
+  unsigned_intHI_type_node = make_unsigned_type (GET_MODE_BITSIZE (HImode));
+  unsigned_intSI_type_node = make_unsigned_type (GET_MODE_BITSIZE (SImode));
+  unsigned_intDI_type_node = make_unsigned_type (GET_MODE_BITSIZE (DImode));
+#if HOST_BITS_PER_WIDE_INT >= 64
+  unsigned_intTI_type_node = make_unsigned_type (GET_MODE_BITSIZE (TImode));
+#endif
 }
 
-/* Return a brand-new alias set.  */
+/* Call this function after calling build_common_tree_nodes and set_sizetype.
+   It will create several other common tree nodes.  */
 
-int
-new_alias_set ()
-{
-  static int last_alias_set;
-  if (flag_strict_aliasing)
-    return ++last_alias_set;
+void
+build_common_tree_nodes_2 (short_double)
+     int short_double;
+{
+  /* Define these next since types below may used them.  */
+  integer_zero_node = build_int_2 (0, 0);
+  integer_one_node = build_int_2 (1, 0);
+
+  size_zero_node = size_int (0);
+  size_one_node = size_int (1);
+  bitsize_zero_node = bitsize_int (0);
+  bitsize_one_node = bitsize_int (1);
+  bitsize_unit_node = bitsize_int (BITS_PER_UNIT);
+
+  void_type_node = make_node (VOID_TYPE);
+  layout_type (void_type_node);
+
+  /* We are not going to have real types in C with less than byte alignment,
+     so we might as well not have any types that claim to have it.  */
+  TYPE_ALIGN (void_type_node) = BITS_PER_UNIT;
+  TYPE_USER_ALIGN (void_type_node) = 0;
+
+  null_pointer_node = build_int_2 (0, 0);
+  TREE_TYPE (null_pointer_node) = build_pointer_type (void_type_node);
+  layout_type (TREE_TYPE (null_pointer_node));
+
+  ptr_type_node = build_pointer_type (void_type_node);
+  const_ptr_type_node
+    = build_pointer_type (build_type_variant (void_type_node, 1, 0));
+
+  float_type_node = make_node (REAL_TYPE);
+  TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE;
+  layout_type (float_type_node);
+
+  double_type_node = make_node (REAL_TYPE);
+  if (short_double)
+    TYPE_PRECISION (double_type_node) = FLOAT_TYPE_SIZE;
   else
-    return 0;
+    TYPE_PRECISION (double_type_node) = DOUBLE_TYPE_SIZE;
+  layout_type (double_type_node);
+
+  long_double_type_node = make_node (REAL_TYPE);
+  TYPE_PRECISION (long_double_type_node) = LONG_DOUBLE_TYPE_SIZE;
+  layout_type (long_double_type_node);
+
+  complex_integer_type_node = make_node (COMPLEX_TYPE);
+  TREE_TYPE (complex_integer_type_node) = integer_type_node;
+  layout_type (complex_integer_type_node);
+
+  complex_float_type_node = make_node (COMPLEX_TYPE);
+  TREE_TYPE (complex_float_type_node) = float_type_node;
+  layout_type (complex_float_type_node);
+
+  complex_double_type_node = make_node (COMPLEX_TYPE);
+  TREE_TYPE (complex_double_type_node) = double_type_node;
+  layout_type (complex_double_type_node);
+
+  complex_long_double_type_node = make_node (COMPLEX_TYPE);
+  TREE_TYPE (complex_long_double_type_node) = long_double_type_node;
+  layout_type (complex_long_double_type_node);
+
+#ifdef BUILD_VA_LIST_TYPE
+  BUILD_VA_LIST_TYPE(va_list_type_node);
+#else
+  va_list_type_node = ptr_type_node;
+#endif
+
+  V4SF_type_node = make_node (VECTOR_TYPE);
+  TREE_TYPE (V4SF_type_node) = float_type_node;
+  TYPE_MODE (V4SF_type_node) = V4SFmode;
+  finish_vector_type (V4SF_type_node);
+
+  V4SI_type_node = make_node (VECTOR_TYPE);
+  TREE_TYPE (V4SI_type_node) = intSI_type_node;
+  TYPE_MODE (V4SI_type_node) = V4SImode;
+  finish_vector_type (V4SI_type_node);
+
+  V2SI_type_node = make_node (VECTOR_TYPE);
+  TREE_TYPE (V2SI_type_node) = intSI_type_node;
+  TYPE_MODE (V2SI_type_node) = V2SImode;
+  finish_vector_type (V2SI_type_node);
+
+  V4HI_type_node = make_node (VECTOR_TYPE);
+  TREE_TYPE (V4HI_type_node) = intHI_type_node;
+  TYPE_MODE (V4HI_type_node) = V4HImode;
+  finish_vector_type (V4HI_type_node);
+
+  V8QI_type_node = make_node (VECTOR_TYPE);
+  TREE_TYPE (V8QI_type_node) = intQI_type_node;
+  TYPE_MODE (V8QI_type_node) = V8QImode;
+  finish_vector_type (V8QI_type_node);
 }