OSDN Git Service

* pa.c (pa_reorg): Fix typo.
[pf3gnuchains/gcc-fork.git] / gcc / tree.c
index 95be365..eb5f6bf 100644 (file)
@@ -1,5 +1,5 @@
 /* Language-independent node constructors for parse phase of GNU compiler.
-   Copyright (C) 1987, 1988, 1992, 1993, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 92, 93, 94, 1995 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -66,6 +66,17 @@ 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;
+
+/* 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.
@@ -264,7 +275,6 @@ static int next_type_uid = 1;
 extern char *mode_name[];
 
 void gcc_obstack_init ();
-static tree stabilize_reference_1 ();
 \f
 /* Init the principal obstacks.  */
 
@@ -316,11 +326,15 @@ gcc_obstack_init (obstack)
 }
 
 /* Save all variables describing the current status into the structure *P.
-   This is used before starting a nested function.  */
+   This is used before starting a nested function.
+
+   CONTEXT is the decl_function_context for the function we're about to
+   compile; if it isn't current_function_decl, we have to play some games.  */
 
 void
-save_tree_status (p)
+save_tree_status (p, context)
      struct function *p;
+     tree context;
 {
   p->all_types_permanent = all_types_permanent;
   p->momentary_stack = momentary_stack;
@@ -333,11 +347,42 @@ save_tree_status (p)
   p->expression_obstack = expression_obstack;
   p->saveable_obstack = saveable_obstack;
   p->rtl_obstack = rtl_obstack;
+  p->inline_obstacks = inline_obstacks;
 
-  /* 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;
+  if (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;
+       }
+
+      current = ((struct simple_obstack_stack *)
+                xmalloc (sizeof (struct simple_obstack_stack)));
+
+      current->obstack = (struct obstack *) xmalloc (sizeof (struct obstack));
+      function_maybepermanent_obstack = current->obstack;
+      gcc_obstack_init (function_maybepermanent_obstack);
+
+      current->next = *head;
+      *head = current;
+    }      
+
+  maybepermanent_firstobj
+    = (char *) obstack_finish (function_maybepermanent_obstack);
 
   function_obstack = (struct obstack *) xmalloc (sizeof (struct obstack));
   gcc_obstack_init (function_obstack);
@@ -348,8 +393,6 @@ save_tree_status (p)
 
   momentary_firstobj = (char *) obstack_finish (&momentary_obstack);
   momentary_function_firstobj = momentary_firstobj;
-  maybepermanent_firstobj
-    = (char *) obstack_finish (function_maybepermanent_obstack);
 }
 
 /* Restore all variables describing the current status from the structure *P.
@@ -367,10 +410,10 @@ restore_tree_status (p)
   /* 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.  */
+     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.  */
   obstack_free (function_maybepermanent_obstack, maybepermanent_firstobj);
 
   obstack_free (function_obstack, 0);
@@ -385,6 +428,7 @@ restore_tree_status (p)
   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.
@@ -401,6 +445,7 @@ 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
@@ -525,9 +570,20 @@ permanent_allocation (function_end)
     }
   else
     obstack_free (&momentary_obstack, momentary_firstobj);
-  obstack_free (&maybepermanent_obstack, maybepermanent_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;
@@ -744,6 +800,15 @@ push_momentary ()
   expression_obstack = &momentary_obstack;
 }
 
+/* Set things up so the next clear_momentary will only clear memory
+   past our present position in momentary_obstack.  */
+
+void
+preserve_momentary ()
+{
+  momentary_stack->base = (char *) obstack_base (&momentary_obstack);
+}
+
 /* Free all the storage in the current momentary-allocation level.
    In C, this happens at the end of each statement.  */
 
@@ -1407,7 +1472,8 @@ make_tree_vec (len)
   return t;
 }
 \f
-/* Return 1 if EXPR is the integer constant zero.  */
+/* Return 1 if EXPR is the integer constant zero or a complex constant
+   of zero.  */
 
 int
 integer_zerop (expr)
@@ -1415,12 +1481,16 @@ integer_zerop (expr)
 {
   STRIP_NOPS (expr);
 
-  return (TREE_CODE (expr) == INTEGER_CST
-         && TREE_INT_CST_LOW (expr) == 0
-         && TREE_INT_CST_HIGH (expr) == 0);
+  return ((TREE_CODE (expr) == INTEGER_CST
+          && TREE_INT_CST_LOW (expr) == 0
+          && TREE_INT_CST_HIGH (expr) == 0)
+         || (TREE_CODE (expr) == COMPLEX_CST
+             && integer_zerop (TREE_REALPART (expr))
+             && integer_zerop (TREE_IMAGPART (expr))));
 }
 
-/* Return 1 if EXPR is the integer constant one.  */
+/* Return 1 if EXPR is the integer constant one or the corresponding
+   complex constant.  */
 
 int
 integer_onep (expr)
@@ -1428,13 +1498,16 @@ integer_onep (expr)
 {
   STRIP_NOPS (expr);
 
-  return (TREE_CODE (expr) == INTEGER_CST
-         && TREE_INT_CST_LOW (expr) == 1
-         && TREE_INT_CST_HIGH (expr) == 0);
+  return ((TREE_CODE (expr) == INTEGER_CST
+          && TREE_INT_CST_LOW (expr) == 1
+          && TREE_INT_CST_HIGH (expr) == 0)
+         || (TREE_CODE (expr) == COMPLEX_CST
+             && integer_onep (TREE_REALPART (expr))
+             && integer_zerop (TREE_IMAGPART (expr))));
 }
 
-/* Return 1 if EXPR is an integer containing all 1's
-   in as much precision as it contains.  */
+/* Return 1 if EXPR is an integer containing all 1's in as much precision as
+   it contains.  Likewise for the corresponding complex constant.  */
 
 int
 integer_all_onesp (expr)
@@ -1445,7 +1518,12 @@ integer_all_onesp (expr)
 
   STRIP_NOPS (expr);
 
-  if (TREE_CODE (expr) != INTEGER_CST)
+  if (TREE_CODE (expr) == COMPLEX_CST
+      && integer_all_onesp (TREE_REALPART (expr))
+      && integer_zerop (TREE_IMAGPART (expr)))
+    return 1;
+
+  else if (TREE_CODE (expr) != INTEGER_CST)
     return 0;
 
   uns = TREE_UNSIGNED (TREE_TYPE (expr));
@@ -1487,6 +1565,11 @@ integer_pow2p (expr)
 
   STRIP_NOPS (expr);
 
+  if (TREE_CODE (expr) == COMPLEX_CST
+      && integer_pow2p (TREE_REALPART (expr))
+      && integer_zerop (TREE_IMAGPART (expr)))
+    return 1;
+
   if (TREE_CODE (expr) != INTEGER_CST)
     return 0;
 
@@ -1508,11 +1591,14 @@ real_zerop (expr)
 {
   STRIP_NOPS (expr);
 
-  return (TREE_CODE (expr) == REAL_CST
-         && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst0));
+  return ((TREE_CODE (expr) == REAL_CST
+          && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst0))
+         || (TREE_CODE (expr) == COMPLEX_CST
+             && real_zerop (TREE_REALPART (expr))
+             && real_zerop (TREE_IMAGPART (expr))));
 }
 
-/* Return 1 if EXPR is the real constant one.  */
+/* Return 1 if EXPR is the real constant one in real or complex form.  */
 
 int
 real_onep (expr)
@@ -1520,8 +1606,11 @@ real_onep (expr)
 {
   STRIP_NOPS (expr);
 
-  return (TREE_CODE (expr) == REAL_CST
-         && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst1));
+  return ((TREE_CODE (expr) == REAL_CST
+          && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst1))
+         || (TREE_CODE (expr) == COMPLEX_CST
+             && real_onep (TREE_REALPART (expr))
+             && real_zerop (TREE_IMAGPART (expr))));
 }
 
 /* Return 1 if EXPR is the real constant two.  */
@@ -1532,8 +1621,11 @@ real_twop (expr)
 {
   STRIP_NOPS (expr);
 
-  return (TREE_CODE (expr) == REAL_CST
-         && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst2));
+  return ((TREE_CODE (expr) == REAL_CST
+          && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst2))
+         || (TREE_CODE (expr) == COMPLEX_CST
+             && real_twop (TREE_REALPART (expr))
+             && real_zerop (TREE_IMAGPART (expr))));
 }
 
 /* Nonzero if EXP is a constant or a cast of a constant.  */
@@ -1598,7 +1690,7 @@ binfo_member (elem, list)
   return NULL_TREE;
 }
 
-/* Return nonzero if ELEM is part of the chain CHAIN.  */
+/* Return nonzero if ELEM is part of the chain CHAIN. */
 
 int
 chain_member (elem, chain)
@@ -1614,6 +1706,41 @@ chain_member (elem, chain)
   return 0;
 }
 
+/* Return nonzero if ELEM is equal to TREE_VALUE (CHAIN) for any piece of
+   chain CHAIN. */
+
+int
+chain_member_value (elem, chain)
+     tree elem, chain;
+{
+  while (chain)
+    {
+      if (elem == TREE_VALUE (chain))
+       return 1;
+      chain = TREE_CHAIN (chain);
+    }
+
+  return 0;
+}
+
+/* Return nonzero if ELEM is equal to TREE_PURPOSE (TREE_VALUE (CHAIN)) 
+   for any piece of chain CHAIN. */
+
+int
+chain_member_purpose (elem, chain)
+     tree elem, chain;
+{
+
+  while (chain)
+    {
+      if (elem == TREE_PURPOSE (TREE_VALUE (chain)))
+       return 1;
+      chain = TREE_CHAIN (chain);
+    }
+
+  return 0;
+}
+
 /* Return the length of a chain of nodes chained through TREE_CHAIN.
    We expect a null pointer to mark the end of the chain.
    This is the Lisp primitive `length'.  */
@@ -1907,11 +2034,9 @@ staticp (arg)
   switch (TREE_CODE (arg))
     {
     case FUNCTION_DECL:
-      /* Nested functions aren't static.  Since taking their address
+      /* Nested functions aren't static, since taking their address
         involves a trampoline.  */
-      if (decl_function_context (arg) != 0)
-       return 0;
-      /* ... fall through ... */
+       return decl_function_context (arg) == 0;
     case VAR_DECL:
       return TREE_STATIC (arg) || DECL_EXTERNAL (arg);
 
@@ -2362,6 +2487,13 @@ stabilize_reference (ref)
                         stabilize_reference (TREE_OPERAND (ref, 1)));
       break;
 
+    case RTL_EXPR:
+      result = build1 (INDIRECT_REF, TREE_TYPE (ref),
+                      save_expr (build1 (ADDR_EXPR,
+                                         build_pointer_type (TREE_TYPE (ref)),
+                                         ref)));
+      break;
+
 
       /* If arg isn't a kind of lvalue we recognize, make no change.
         Caller should recognize the error for an invalid lvalue.  */
@@ -2394,7 +2526,7 @@ stabilize_reference (ref)
    operator should be allowed, and that cse should take care of coalescing
    multiple utterances of the same expression should that prove fruitful.  */
 
-static tree
+tree
 stabilize_reference_1 (e)
      tree e;
 {
@@ -2719,11 +2851,21 @@ build_block (vars, tags, subblocks, supercontext, chain)
   return block;
 }
 \f
+/* Return a declaration like DDECL except that its DECL_MACHINE_ATTRIBUTE
+   is ATTRIBUTE. */
+
+tree
+build_decl_attribute_variant (ddecl, attribute)
+     tree ddecl, attribute;
+{
+  DECL_MACHINE_ATTRIBUTES (ddecl) = attribute;
+  return ddecl;
+}
+
 /* Return a type like TTYPE except that its TYPE_ATTRIBUTE
    is ATTRIBUTE.
 
-   Such modified types already made are recorded so that duplicates
-   are not made. */
+   Record such modified types already made so we don't make duplicates.  */
 
 tree
 build_type_attribute_variant (ttype, attribute)
@@ -2777,6 +2919,70 @@ build_type_attribute_variant (ttype, attribute)
 
   return ttype;
 }
+
+/* Return a 1 if ATTR_NAME and ATTR_ARGS is valid for either declaration DECL
+   or type TYPE and 0 otherwise.  Validity is determined the configuration
+   macros VALID_MACHINE_DECL_ATTRIBUTE and VALID_MACHINE_TYPE_ATTRIBUTE. */
+
+int
+valid_machine_attribute (attr_name, attr_args, decl, type)
+     tree attr_name, attr_args;
+     tree decl;
+     tree type;
+{
+  int valid = 0;
+  tree decl_attr_list = decl != 0 ? DECL_MACHINE_ATTRIBUTES (decl) : 0;
+  tree type_attr_list = TYPE_ATTRIBUTES (type);
+
+  /* For now, we don't support args.  */
+  if (attr_args != 0)
+    return 0;
+
+#ifdef VALID_MACHINE_DECL_ATTRIBUTE
+  if (decl != 0
+      && VALID_MACHINE_DECL_ATTRIBUTE (decl, decl_attr_list, attr_name))
+    {
+      tree attr_list;
+      int in_list = 0;
+
+      for (attr_list = decl_attr_list; 
+           attr_list;
+           attr_list = TREE_CHAIN (attr_list))
+       if (TREE_VALUE (attr_list) == attr_name)
+         in_list = 1;
+
+      if (! in_list)
+        decl_attr_list = tree_cons (NULL_TREE, attr_name, decl_attr_list);
+
+      decl = build_decl_attribute_variant (decl, decl_attr_list);
+      valid = 1;
+    }
+#endif
+
+#ifdef VALID_MACHINE_TYPE_ATTRIBUTE
+  if (VALID_MACHINE_TYPE_ATTRIBUTE (type, type_attr_list, attr_name))
+    {
+      tree attr_list;
+      int in_list = 0;
+
+      for (attr_list = type_attr_list;
+           attr_list;
+          attr_list = TREE_CHAIN (attr_list))
+       if (TREE_VALUE (attr_list) == attr_name)
+         in_list = 1;
+
+      if (! in_list)
+        type_attr_list = tree_cons (NULL_TREE, attr_name, type_attr_list);
+
+      type = build_type_attribute_variant (type, type_attr_list);
+      if (decl != 0)
+       TREE_TYPE (decl) = type;
+      valid = 1;
+    }
+#endif
+
+  return valid;
+}
 \f
 /* Return a type like TYPE except that its TYPE_READONLY is CONSTP
    and its TYPE_VOLATILE is VOLATILEP.
@@ -3850,7 +4056,7 @@ decl_function_context (decl)
     {
       if (TREE_CODE (context) == RECORD_TYPE
          || TREE_CODE (context) == UNION_TYPE)
-       context = TYPE_CONTEXT (context);
+       context = NULL_TREE;
       else if (TREE_CODE (context) == TYPE_DECL)
        context = DECL_CONTEXT (context);
       else if (TREE_CODE (context) == BLOCK)
@@ -4001,3 +4207,100 @@ get_file_function_name (kind)
 
   return get_identifier (buf);
 }
+\f
+/* Expand (the constant part of) a SET_TYPE CONTRUCTOR node.
+   The result is placed in BUFFER (which has length BIT_SIZE),
+   with one bit in each char ('\000' or '\001').
+
+   If the constructor is constant, NULL_TREE is returned.
+   Otherwise, a TREE_LIST of the non-constant elements is emitted. */
+
+tree
+get_set_constructor_bits (init, buffer, bit_size)
+     tree init;
+     char *buffer;
+     int bit_size;
+{
+  int i;
+  tree vals;
+  HOST_WIDE_INT domain_min
+    = TREE_INT_CST_LOW (TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (init))));
+  tree non_const_bits = NULL_TREE;
+  for (i = 0; i < bit_size; i++)
+    buffer[i] = 0;
+
+  for (vals = TREE_OPERAND (init, 1); 
+       vals != NULL_TREE; vals = TREE_CHAIN (vals))
+    {
+      if (TREE_CODE (TREE_VALUE (vals)) != INTEGER_CST
+         || (TREE_PURPOSE (vals) != NULL_TREE
+             && TREE_CODE (TREE_PURPOSE (vals)) != INTEGER_CST))
+       non_const_bits =
+         tree_cons (TREE_PURPOSE (vals), TREE_VALUE (vals), non_const_bits);
+      else if (TREE_PURPOSE (vals) != NULL_TREE)
+       {
+         /* Set a range of bits to ones. */
+         HOST_WIDE_INT lo_index
+           = 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 ();
+         for ( ; lo_index <= hi_index; lo_index++)
+           buffer[lo_index] = 1;
+       }
+      else
+       {
+         /* Set a single bit to one. */
+         HOST_WIDE_INT index
+           = TREE_INT_CST_LOW (TREE_VALUE (vals)) - domain_min;
+         if (index < 0 || index >= bit_size)
+           {
+             error ("invalid initializer for bit string");
+             return NULL_TREE;
+           }
+         buffer[index] = 1;
+       }
+    }
+  return non_const_bits;
+}
+
+/* Expand (the constant part of) a SET_TYPE CONTRUCTOR node.
+   The result is placed in BUFFER (which is an array of bytes).
+   If the constructor is constant, NULL_TREE is returned.
+   Otherwise, a TREE_LIST of the non-constant elements is emitted. */
+
+tree
+get_set_constructor_bytes (init, buffer, wd_size)
+     tree init;
+     unsigned char *buffer;
+     int wd_size;
+{
+  int i;
+  tree vals = TREE_OPERAND (init, 1);
+  int set_word_size = BITS_PER_UNIT;
+  int bit_size = wd_size * set_word_size;
+  int bit_pos = 0;
+  unsigned char *bytep = buffer;
+  char *bit_buffer = (char*)alloca(bit_size);
+  tree non_const_bits = get_set_constructor_bits (init, bit_buffer, bit_size);
+
+  for (i = 0; i < wd_size; i++)
+    buffer[i] = 0;
+
+  for (i = 0; i < bit_size; i++)
+    {
+      if (bit_buffer[i])
+       {
+         if (BITS_BIG_ENDIAN)
+           *bytep |= (1 << (set_word_size - 1 - bit_pos));
+         else
+           *bytep |= 1 << bit_pos;
+       }
+      bit_pos++;
+      if (bit_pos >= set_word_size)
+       bit_pos = 0, bytep++;
+    }
+  return non_const_bits;
+}