/* 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.
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.
extern char *mode_name[];
void gcc_obstack_init ();
-static tree stabilize_reference_1 ();
\f
/* Init the principal obstacks. */
}
/* 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;
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);
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.
/* 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);
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.
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
}
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;
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. */
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)
{
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)
{
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)
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));
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;
{
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)
{
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. */
{
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. */
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)
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'. */
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);
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. */
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;
{
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)
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.
{
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)
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;
+}