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
- the bodies and parameters of function definitions. */
+/* Objects allocated on this obstack last forever. */
struct obstack permanent_obstack;
-/* The initial RTL, and all ..._TYPE nodes, in a function
- are allocated in this obstack. Usually they are freed at the
- end of the function, but if the function is inline they are saved.
- For top-level functions, this is maybepermanent_obstack.
- Separate obstacks are made for nested functions. */
-
-struct obstack *function_maybepermanent_obstack;
-
-/* This is the function_maybepermanent_obstack for top-level functions. */
-
-struct obstack maybepermanent_obstack;
-
-/* 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.
- Separate obstacks are made for nested functions. */
-
-struct obstack *function_obstack;
-
-/* This is used for reading initializers of global variables. */
-
-struct obstack temporary_obstack;
-
-/* The tree nodes of an expression are allocated
- in this obstack, and all are freed at the end of the expression. */
-
-struct obstack momentary_obstack;
-
-/* The tree nodes of a declarator are allocated
- in this obstack, and all are freed when the declarator
- has been parsed. */
-
-static struct obstack temp_decl_obstack;
-
-/* This points at either permanent_obstack
- or the current function_maybepermanent_obstack. */
-
-struct obstack *saveable_obstack;
-
-/* This is same as saveable_obstack during parse and expansion phase;
- it points to the current function's obstack during optimization.
- This is the obstack to be used for creating rtl objects. */
-
-struct obstack *rtl_obstack;
-
-/* This points at either permanent_obstack or the current function_obstack. */
-
-struct obstack *current_obstack;
-
-/* This points at either permanent_obstack or the current function_obstack
- or momentary_obstack. */
-
-struct obstack *expression_obstack;
-
-/* Stack of obstack selections for push_obstacks and pop_obstacks. */
-
-struct obstack_stack
-{
- struct obstack_stack *next;
- struct obstack *current;
- struct obstack *saveable;
- struct obstack *expression;
- struct obstack *rtl;
-};
-
-struct obstack_stack *obstack_stack;
-
-/* Obstack for allocating struct obstack_stack entries. */
-
-static struct obstack obstack_stack_obstack;
-
-/* Addresses of first objects in some obstacks.
- This is for freeing their entire contents. */
-char *maybepermanent_firstobj;
-char *temporary_firstobj;
-char *momentary_firstobj;
-char *temp_decl_firstobj;
-
-/* This is used to preserve objects (mainly array initializers) that need to
- live until the end of the current function, but no further. */
-char *momentary_function_firstobj;
-
-/* Nonzero means all ..._TYPE nodes should be allocated permanently. */
-
-int all_types_permanent;
-
-/* Stack of places to restore the momentary obstack back to. */
-
-struct momentary_level
-{
- /* Pointer back to previous such level. */
- struct momentary_level *prev;
- /* First object allocated within this level. */
- char *base;
- /* Value of expression_obstack saved at entry to this level. */
- struct obstack *obstack;
-};
-
-struct momentary_level *momentary_stack;
-
/* Table indexed by tree code giving a string containing a character
classifying the tree code. Possibilities are
t, d, s, c, r, <, 1, 2 and e. See tree.def for details. */
"lang_type kinds"
};
-/* Hash table for uniquizing IDENTIFIER_NODEs by name. */
-
-#define MAX_HASH_TABLE 1009
-static tree hash_table[MAX_HASH_TABLE]; /* id hash buckets */
-
-/* 0 while creating built-in identifiers. */
-static int do_identifier_warnings;
-
/* Unique id for next decl created. */
static int next_decl_uid;
/* Unique id for next type created. */
static void print_type_hash_statistics PARAMS((void));
static int mark_hash_entry PARAMS((void **, void *));
static void finish_vector_type PARAMS((tree));
+static int mark_tree_hashtable_entry PARAMS((void **, void *));
/* If non-null, these are language-specific helper functions for
unsave_expr_now. If present, LANG_UNSAVE is called before its
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>")
+/* If non-null, these are language-specific helper functions for
+ unsafe_for_reeval. Return negative to not handle some tree. */
+int (*lang_unsafe_for_reeval) PARAMS ((tree));
\f
tree global_trees[TI_MAX];
tree integer_types[itk_none];
void
init_obstacks ()
{
- gcc_obstack_init (&obstack_stack_obstack);
gcc_obstack_init (&permanent_obstack);
- gcc_obstack_init (&temporary_obstack);
- temporary_firstobj = (char *) obstack_alloc (&temporary_obstack, 0);
- gcc_obstack_init (&momentary_obstack);
- momentary_firstobj = (char *) obstack_alloc (&momentary_obstack, 0);
- momentary_function_firstobj = momentary_firstobj;
- gcc_obstack_init (&maybepermanent_obstack);
- maybepermanent_firstobj
- = (char *) obstack_alloc (&maybepermanent_obstack, 0);
- gcc_obstack_init (&temp_decl_obstack);
- temp_decl_firstobj = (char *) obstack_alloc (&temp_decl_obstack, 0);
-
- function_obstack = &temporary_obstack;
- function_maybepermanent_obstack = &maybepermanent_obstack;
- current_obstack = &permanent_obstack;
- expression_obstack = &permanent_obstack;
- rtl_obstack = saveable_obstack = &permanent_obstack;
-
- /* 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);
(void (*) PARAMS ((void *))) OBSTACK_CHUNK_FREE);
}
-/* Save all variables describing the current status into the structure
- *P. This function is called whenever we start compiling one
- function in the midst of compiling another. For example, when
- compiling a nested function, or, in C++, a template instantiation
- that is required by the function we are currently compiling.
-
- 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)
- struct function *p;
-{
- p->all_types_permanent = all_types_permanent;
- p->momentary_stack = momentary_stack;
- p->maybepermanent_firstobj = maybepermanent_firstobj;
- p->temporary_firstobj = temporary_firstobj;
- p->momentary_firstobj = momentary_firstobj;
- p->momentary_function_firstobj = momentary_function_firstobj;
- p->function_obstack = function_obstack;
- p->function_maybepermanent_obstack = function_maybepermanent_obstack;
- p->current_obstack = current_obstack;
- p->expression_obstack = expression_obstack;
- p->saveable_obstack = saveable_obstack;
- p->rtl_obstack = rtl_obstack;
-
- function_maybepermanent_obstack
- = (struct obstack *) xmalloc (sizeof (struct obstack));
- gcc_obstack_init (function_maybepermanent_obstack);
- maybepermanent_firstobj
- = (char *) obstack_finish (function_maybepermanent_obstack);
-
- function_obstack = (struct obstack *) xmalloc (sizeof (struct obstack));
- gcc_obstack_init (function_obstack);
-
- current_obstack = &permanent_obstack;
- expression_obstack = &permanent_obstack;
- rtl_obstack = saveable_obstack = &permanent_obstack;
-
- temporary_firstobj = (char *) obstack_alloc (&temporary_obstack, 0);
- momentary_firstobj = (char *) obstack_finish (&momentary_obstack);
- momentary_function_firstobj = momentary_firstobj;
-}
-
-/* Restore all variables describing the current status from the structure *P.
- This is used after a nested function. */
-
-void
-restore_tree_status (p)
- struct function *p;
-{
- all_types_permanent = p->all_types_permanent;
- momentary_stack = p->momentary_stack;
-
- obstack_free (&momentary_obstack, momentary_function_firstobj);
-
- /* Free saveable storage used by the function just compiled and not
- saved. */
- obstack_free (function_maybepermanent_obstack, maybepermanent_firstobj);
- if (obstack_empty_p (function_maybepermanent_obstack))
- {
- obstack_free (function_maybepermanent_obstack, NULL);
- free (function_maybepermanent_obstack);
- }
-
- obstack_free (&temporary_obstack, temporary_firstobj);
- obstack_free (&momentary_obstack, momentary_function_firstobj);
-
- obstack_free (function_obstack, NULL);
- free (function_obstack);
-
- temporary_firstobj = p->temporary_firstobj;
- momentary_firstobj = p->momentary_firstobj;
- momentary_function_firstobj = p->momentary_function_firstobj;
- maybepermanent_firstobj = p->maybepermanent_firstobj;
- function_obstack = p->function_obstack;
- function_maybepermanent_obstack = p->function_maybepermanent_obstack;
- current_obstack = p->current_obstack;
- expression_obstack = p->expression_obstack;
- saveable_obstack = p->saveable_obstack;
- rtl_obstack = p->rtl_obstack;
-}
\f
-/* Start allocating on the temporary (per function) obstack.
- This is done in start_function before parsing the function body,
- and before each initialization at top level, and to go back
- to temporary allocation after doing permanent_allocation. */
-
-void
-temporary_allocation ()
-{
- /* Note that function_obstack at top level points to temporary_obstack.
- But within a nested function context, it is a separate obstack. */
- current_obstack = function_obstack;
- expression_obstack = function_obstack;
- rtl_obstack = saveable_obstack = function_maybepermanent_obstack;
- momentary_stack = 0;
-}
-
-/* Start allocating on the permanent obstack but don't
- free the temporary data. After calling this, call
- `permanent_allocation' to fully resume permanent allocation status. */
-
-void
-end_temporary_allocation ()
-{
- current_obstack = &permanent_obstack;
- expression_obstack = &permanent_obstack;
- rtl_obstack = saveable_obstack = &permanent_obstack;
-}
-
-/* Resume allocating on the temporary obstack, undoing
- effects of `end_temporary_allocation'. */
-
-void
-resume_temporary_allocation ()
-{
- current_obstack = function_obstack;
- expression_obstack = function_obstack;
- rtl_obstack = saveable_obstack = function_maybepermanent_obstack;
-}
-
-/* While doing temporary allocation, switch to allocating in such a
- way as to save all nodes if the function is inlined. Call
- resume_temporary_allocation to go back to ordinary temporary
- allocation. */
-
-void
-saveable_allocation ()
-{
- /* Note that function_obstack at top level points to temporary_obstack.
- But within a nested function context, it is a separate obstack. */
- expression_obstack = current_obstack = saveable_obstack;
-}
-
-/* Switch to current obstack CURRENT and maybepermanent obstack SAVEABLE,
- recording the previously current obstacks on a stack.
- This does not free any storage in any obstack. */
-
-void
-push_obstacks (current, saveable)
- struct obstack *current, *saveable;
-{
- struct obstack_stack *p;
-
- p = (struct obstack_stack *) obstack_alloc (&obstack_stack_obstack,
- (sizeof (struct obstack_stack)));
-
- p->current = current_obstack;
- p->saveable = saveable_obstack;
- p->expression = expression_obstack;
- p->rtl = rtl_obstack;
- p->next = obstack_stack;
- obstack_stack = p;
-
- current_obstack = current;
- expression_obstack = current;
- rtl_obstack = saveable_obstack = saveable;
-}
-
-/* Save the current set of obstacks, but don't change them. */
-
-void
-push_obstacks_nochange ()
-{
- struct obstack_stack *p;
-
- p = (struct obstack_stack *) obstack_alloc (&obstack_stack_obstack,
- (sizeof (struct obstack_stack)));
-
- p->current = current_obstack;
- p->saveable = saveable_obstack;
- p->expression = expression_obstack;
- p->rtl = rtl_obstack;
- p->next = obstack_stack;
- obstack_stack = p;
-}
-
-/* Pop the obstack selection stack. */
-
-void
-pop_obstacks ()
-{
- struct obstack_stack *p;
-
- p = obstack_stack;
- obstack_stack = p->next;
-
- current_obstack = p->current;
- saveable_obstack = p->saveable;
- expression_obstack = p->expression;
- rtl_obstack = p->rtl;
-
- obstack_free (&obstack_stack_obstack, p);
-}
-
-/* Nonzero if temporary allocation is currently in effect.
- Zero if currently doing permanent allocation. */
-
-int
-allocation_temporary_p ()
-{
- return current_obstack != &permanent_obstack;
-}
-
-/* Go back to allocating on the permanent obstack
- and free everything in the temporary obstack.
-
- FUNCTION_END is true only if we have just finished compiling a function.
- In that case, we also free preserved initial values on the momentary
- obstack. */
-
-void
-permanent_allocation (function_end)
- int function_end;
-{
- /* Free up previous temporary obstack data */
- obstack_free (&temporary_obstack, temporary_firstobj);
- if (function_end)
- {
- obstack_free (&momentary_obstack, momentary_function_firstobj);
- momentary_firstobj = momentary_function_firstobj;
- }
- else
- obstack_free (&momentary_obstack, momentary_firstobj);
-
- obstack_free (function_maybepermanent_obstack, maybepermanent_firstobj);
- obstack_free (&temp_decl_obstack, temp_decl_firstobj);
-
- current_obstack = &permanent_obstack;
- expression_obstack = &permanent_obstack;
- rtl_obstack = saveable_obstack = &permanent_obstack;
-}
-
-/* Save permanently everything on the maybepermanent_obstack. */
-
-void
-preserve_data ()
-{
- maybepermanent_firstobj
- = (char *) obstack_alloc (function_maybepermanent_obstack, 0);
-}
-
-void
-preserve_initializer ()
-{
- struct momentary_level *tem;
- char *old_momentary;
-
- temporary_firstobj
- = (char *) obstack_alloc (&temporary_obstack, 0);
- maybepermanent_firstobj
- = (char *) obstack_alloc (function_maybepermanent_obstack, 0);
-
- old_momentary = momentary_firstobj;
- momentary_firstobj
- = (char *) obstack_alloc (&momentary_obstack, 0);
- if (momentary_firstobj != old_momentary)
- for (tem = momentary_stack; tem; tem = tem->prev)
- tem->base = momentary_firstobj;
-}
-
-/* Start allocating new rtl in current_obstack.
- Use resume_temporary_allocation
- to go back to allocating rtl in saveable_obstack. */
-
-void
-rtl_in_current_obstack ()
-{
- rtl_obstack = current_obstack;
-}
-
-/* Start allocating rtl from saveable_obstack. Intended to be used after
- a call to push_obstacks_nochange. */
-
-void
-rtl_in_saveable_obstack ()
-{
- rtl_obstack = saveable_obstack;
-}
-\f
-/* Allocate SIZE bytes in the current obstack
- and return a pointer to them.
- In practice the current obstack is always the temporary one. */
-
-char *
-oballoc (size)
- int size;
-{
- return (char *) obstack_alloc (current_obstack, size);
-}
-
-/* Free the object PTR in the current obstack
- as well as everything allocated since PTR.
- In practice the current obstack is always the temporary one. */
-
-void
-obfree (ptr)
- char *ptr;
-{
- obstack_free (current_obstack, ptr);
-}
-
/* Allocate SIZE bytes in the permanent obstack
and return a pointer to them. */
long size;
{
char *rval = (char *) obstack_alloc (&permanent_obstack, nelem * size);
- bzero (rval, nelem * size);
+ memset (rval, 0, nelem * size);
return rval;
}
-/* Allocate SIZE bytes in the saveable obstack
- and return a pointer to them. */
-
-char *
-savealloc (size)
- int size;
-{
- return (char *) obstack_alloc (saveable_obstack, size);
-}
-
-/* Allocate SIZE bytes in the expression obstack
- and return a pointer to them. */
-
-char *
-expralloc (size)
- int size;
-{
- return (char *) obstack_alloc (expression_obstack, size);
-}
-\f
-/* Print out which obstack an object is in. */
-
-void
-print_obstack_name (object, file, prefix)
- char *object;
- FILE *file;
- const char *prefix;
-{
- struct obstack *obstack = NULL;
- const char *obstack_name = NULL;
- struct function *p;
-
- for (p = outer_function_chain; p; p = p->next)
- {
- if (_obstack_allocated_p (p->function_obstack, object))
- {
- obstack = p->function_obstack;
- obstack_name = "containing function obstack";
- }
- if (_obstack_allocated_p (p->function_maybepermanent_obstack, object))
- {
- obstack = p->function_maybepermanent_obstack;
- obstack_name = "containing function maybepermanent obstack";
- }
- }
-
- if (_obstack_allocated_p (&obstack_stack_obstack, object))
- {
- obstack = &obstack_stack_obstack;
- obstack_name = "obstack_stack_obstack";
- }
- else if (_obstack_allocated_p (function_obstack, object))
- {
- obstack = function_obstack;
- obstack_name = "function obstack";
- }
- else if (_obstack_allocated_p (&permanent_obstack, object))
- {
- obstack = &permanent_obstack;
- obstack_name = "permanent_obstack";
- }
- else if (_obstack_allocated_p (&momentary_obstack, object))
- {
- obstack = &momentary_obstack;
- obstack_name = "momentary_obstack";
- }
- else if (_obstack_allocated_p (function_maybepermanent_obstack, object))
- {
- obstack = function_maybepermanent_obstack;
- obstack_name = "function maybepermanent obstack";
- }
- else if (_obstack_allocated_p (&temp_decl_obstack, object))
- {
- obstack = &temp_decl_obstack;
- obstack_name = "temp_decl_obstack";
- }
-
- /* Check to see if the object is in the free area of the obstack. */
- if (obstack != NULL)
- {
- if (object >= obstack->next_free
- && object < obstack->chunk_limit)
- fprintf (file, "%s in free portion of obstack %s",
- prefix, obstack_name);
- else
- fprintf (file, "%s allocated from %s", prefix, obstack_name);
- }
- else
- fprintf (file, "%s not allocated from any obstack", prefix);
-}
-
-void
-debug_obstack (object)
- char *object;
-{
- print_obstack_name (object, stderr, "object");
- fprintf (stderr, ".\n");
-}
-
-/* Return 1 if OBJ is in the permanent obstack.
- This is slow, and should be used only for debugging.
- Use TREE_PERMANENT for other purposes. */
-
-int
-object_permanent_p (obj)
- tree obj;
-{
- return _obstack_allocated_p (&permanent_obstack, obj);
-}
-\f
-/* Start a level of momentary allocation.
- In C, each compound statement has its own level
- and that level is freed at the end of each statement.
- All expression nodes are allocated in the momentary allocation level. */
-
-void
-push_momentary ()
-{
- struct momentary_level *tem
- = (struct momentary_level *) obstack_alloc (&momentary_obstack,
- sizeof (struct momentary_level));
- tem->prev = momentary_stack;
- tem->base = (char *) obstack_base (&momentary_obstack);
- tem->obstack = expression_obstack;
- momentary_stack = tem;
- 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. */
-
-void
-clear_momentary ()
-{
- obstack_free (&momentary_obstack, momentary_stack->base);
-}
-
-/* Discard a level of momentary allocation.
- In C, this happens at the end of each compound statement.
- Restore the status of expression node allocation
- that was in effect before this level was created. */
-
-void
-pop_momentary ()
-{
- struct momentary_level *tem = momentary_stack;
- momentary_stack = tem->prev;
- expression_obstack = tem->obstack;
- /* We can't free TEM from the momentary_obstack, because there might
- be objects above it which have been saved. We can free back to the
- stack of the level we are popping off though. */
- obstack_free (&momentary_obstack, tem->base);
-}
-
-/* Pop back to the previous level of momentary allocation,
- but don't free any momentary data just yet. */
-
-void
-pop_momentary_nofree ()
-{
- struct momentary_level *tem = momentary_stack;
- momentary_stack = tem->prev;
- expression_obstack = tem->obstack;
-}
-
-/* Call when starting to parse a declaration:
- make expressions in the declaration last the length of the function.
- Returns an argument that should be passed to resume_momentary later. */
-
-int
-suspend_momentary ()
-{
- register int tem = expression_obstack == &momentary_obstack;
- expression_obstack = saveable_obstack;
- return tem;
-}
-
-/* Call when finished parsing a declaration:
- restore the treatment of node-allocation that was
- in effect before the suspension.
- YES should be the value previously returned by suspend_momentary. */
-
-void
-resume_momentary (yes)
- int yes;
-{
- if (yes)
- expression_obstack = &momentary_obstack;
-}
-\f
-/* Init the tables indexed by tree code.
- Note that languages can add to these tables to define their own codes. */
-
-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);
-}
-
/* Compute the number of bytes occupied by 'node'. This routine only
looks at TREE_CODE and, if the code is TREE_VEC, TREE_VEC_LENGTH. */
size_t
}
/* 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.
memset ((PTR) t, 0, length);
TREE_SET_CODE (t, code);
- TREE_SET_PERMANENT (t);
switch (type)
{
DECL_IN_SYSTEM_HEADER (t) = in_system_header;
DECL_SOURCE_LINE (t) = lineno;
DECL_SOURCE_FILE (t) =
- (input_filename) ? input_filename : built_in_filename;
+ (input_filename) ? input_filename : "<built-in>";
DECL_UID (t) = next_decl_uid++;
/* Note that we have not yet computed the alias set for this
declaration. */
case 't':
TYPE_UID (t) = next_type_uid++;
- TYPE_ALIGN (t) = 1;
+ TYPE_ALIGN (t) = char_type_node ? TYPE_ALIGN (char_type_node) : 0;
TYPE_USER_ALIGN (t) = 0;
TYPE_MAIN_VARIANT (t) = t;
TYPE_ATTRIBUTES (t) = NULL_TREE;
register size_t length;
length = tree_size (node);
- if (ggc_p)
- t = ggc_alloc_tree (length);
- else
- t = (tree) obstack_alloc (current_obstack, length);
+ t = ggc_alloc_tree (length);
memcpy (t, node, length);
TREE_CHAIN (t) = 0;
else if (TREE_CODE_CLASS (code) == 't')
{
TYPE_UID (t) = next_type_uid++;
- TYPE_OBSTACK (t) = current_obstack;
-
/* The following is so that the debug code for
the copy is different from the original type.
The two statements usually duplicate each other
TYPE_SYMTAB_ADDRESS (t) = 0;
}
- TREE_SET_PERMANENT (t);
-
return t;
}
}
return head;
}
-\f
-#define HASHBITS 30
-
-/* Return an IDENTIFIER_NODE whose name is TEXT (a null-terminated string).
- If an identifier with that name has previously been referred to,
- the same node is returned this time. */
-
-tree
-get_identifier (text)
- register const char *text;
-{
- register int hi;
- register int i;
- register tree idp;
- register int len, hash_len;
-
- /* Compute length of text in len. */
- len = strlen (text);
-
- /* Decide how much of that length to hash on */
- hash_len = len;
- if (warn_id_clash && len > id_clash_len)
- hash_len = id_clash_len;
-
- /* Compute hash code */
- hi = hash_len * 613 + (unsigned) text[0];
- for (i = 1; i < hash_len; i += 2)
- hi = ((hi * 613) + (unsigned) (text[i]));
-
- hi &= (1 << HASHBITS) - 1;
- hi %= MAX_HASH_TABLE;
-
- /* Search table for identifier. */
- for (idp = hash_table[hi]; idp; idp = TREE_CHAIN (idp))
- if (IDENTIFIER_LENGTH (idp) == len
- && IDENTIFIER_POINTER (idp)[0] == text[0]
- && !bcmp (IDENTIFIER_POINTER (idp), text, len))
- /* Return if found. */
- return idp;
-
- /* Not found; optionally warn about a similar identifier. */
- 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))
- {
- warning ("`%s' and `%s' identical in first %d characters",
- IDENTIFIER_POINTER (idp), text, id_clash_len);
- break;
- }
-
- if (TREE_CODE_LENGTH (IDENTIFIER_NODE) < 0)
- abort (); /* set_identifier_size hasn't been called. */
-
- /* Not found, create one, add to chain */
- idp = make_node (IDENTIFIER_NODE);
- IDENTIFIER_LENGTH (idp) = len;
-#ifdef GATHER_STATISTICS
- id_string_size += len;
-#endif
- 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;
- return idp; /* <-- return if created */
-}
-
-/* If an identifier with the name TEXT (a null-terminated string) has
- previously been referred to, return that node; otherwise return
- NULL_TREE. */
-
-tree
-maybe_get_identifier (text)
- register const char *text;
-{
- register int hi;
- register int i;
- register tree idp;
- register int len, hash_len;
-
- /* Compute length of text in len. */
- len = strlen (text);
-
- /* Decide how much of that length to hash on */
- hash_len = len;
- if (warn_id_clash && len > id_clash_len)
- hash_len = id_clash_len;
-
- /* Compute hash code */
- hi = hash_len * 613 + (unsigned) text[0];
- for (i = 1; i < hash_len; i += 2)
- hi = ((hi * 613) + (unsigned) (text[i]));
-
- hi &= (1 << HASHBITS) - 1;
- hi %= MAX_HASH_TABLE;
-
- /* Search table for identifier. */
- for (idp = hash_table[hi]; idp; idp = TREE_CHAIN (idp))
- if (IDENTIFIER_LENGTH (idp) == len
- && IDENTIFIER_POINTER (idp)[0] == text[0]
- && !bcmp (IDENTIFIER_POINTER (idp), text, len))
- return idp; /* <-- return if found */
-
- return NULL_TREE;
-}
-
-/* Enable warnings on similar identifiers (if requested).
- Done after the built-in identifiers are created. */
-
-void
-start_identifier_warnings ()
-{
- do_identifier_warnings = 1;
-}
-
-/* Record the size of an identifier node for the language in use.
- SIZE is the total size in bytes.
- This is called by the language-specific files. This must be
- called before allocating any identifiers. */
-
-void
-set_identifier_size (size)
- int size;
-{
- tree_code_length[(int) IDENTIFIER_NODE]
- = (size - sizeof (struct tree_common)) / sizeof (tree);
-}
\f
/* Return a newly constructed INTEGER_CST node whose constant value
is specified by the two ints LOW and HI.
#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);
+ memset ((char *) &d, 0, sizeof d);
if (! TREE_UNSIGNED (TREE_TYPE (i)))
REAL_VALUE_FROM_INT (d, TREE_INT_CST_LOW (i), TREE_INT_CST_HIGH (i),
int len;
const char *str;
{
- /* Put the string in saveable_obstack since it will be placed in the RTL
- for an "asm" statement and will also be kept around a while if
- deferring constant output in varasm.c. */
-
register tree s = make_node (STRING_CST);
TREE_STRING_LENGTH (s) = len;
- if (ggc_p)
- TREE_STRING_POINTER (s) = ggc_alloc_string (str, len);
- else
- TREE_STRING_POINTER (s) = obstack_copy0 (saveable_obstack, str, len);
+ TREE_STRING_POINTER (s) = ggc_alloc_string (str, len);
return s;
}
{
register tree t;
register int length = (len-1) * sizeof (tree) + sizeof (struct tree_vec);
- register struct obstack *obstack = current_obstack;
#ifdef GATHER_STATISTICS
tree_node_counts[(int)vec_kind]++;
tree_node_sizes[(int)vec_kind] += length;
#endif
- if (ggc_p)
- t = ggc_alloc_tree (length);
- else
- t = (tree) obstack_alloc (obstack, length);
+ t = ggc_alloc_tree (length);
memset ((PTR) t, 0, length);
TREE_SET_CODE (t, TREE_VEC);
TREE_VEC_LENGTH (t) = len;
- TREE_SET_PERMANENT (t);
return t;
}
return t;
}
-/* Similar, but build on the temp_decl_obstack. */
-
-tree
-build_decl_list (parm, value)
- tree 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;
- return node;
-}
-
-/* Similar, but build on the expression_obstack. */
-
-tree
-build_expr_list (parm, value)
- tree 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;
- return node;
-}
-
/* Return a newly created TREE_LIST node whose
purpose and value fields are PARM and VALUE
and whose TREE_CHAIN is CHAIN. */
{
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));
+ node = ggc_alloc_tree (sizeof (struct tree_list));
memset (node, 0, sizeof (struct tree_common));
#endif
TREE_SET_CODE (node, TREE_LIST);
- TREE_SET_PERMANENT (node);
-
TREE_CHAIN (node) = chain;
TREE_PURPOSE (node) = purpose;
TREE_VALUE (node) = value;
return node;
}
-/* Similar, but build on the temp_decl_obstack. */
-
-tree
-decl_tree_cons (purpose, value, chain)
- tree 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;
- return node;
-}
-
-/* Similar, but build on the expression_obstack. */
-
-tree
-expr_tree_cons (purpose, value, chain)
- tree 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;
- return node;
-}
-
-/* Same as `tree_cons' but make a permanent object. */
-
-tree
-perm_tree_cons (purpose, value, chain)
- tree purpose, value, chain;
-{
- register tree node;
- register struct obstack *ambient_obstack = current_obstack;
-
- current_obstack = &permanent_obstack;
- node = tree_cons (purpose, value, chain);
- current_obstack = ambient_obstack;
- return node;
-}
-
-/* Same as `tree_cons', but make this node temporary, regardless. */
-
-tree
-temp_tree_cons (purpose, value, chain)
- tree purpose, value, chain;
-{
- register tree node;
- register struct obstack *ambient_obstack = current_obstack;
-
- current_obstack = &temporary_obstack;
- node = tree_cons (purpose, value, chain);
- current_obstack = ambient_obstack;
- return node;
-}
-
-/* Same as `tree_cons', but save this node if the function's RTL is saved. */
-
-tree
-saveable_tree_cons (purpose, value, chain)
- tree purpose, value, chain;
-{
- register tree node;
- register struct obstack *ambient_obstack = current_obstack;
-
- current_obstack = saveable_obstack;
- node = tree_cons (purpose, value, chain);
- current_obstack = ambient_obstack;
- return node;
-}
\f
/* Return the size nominally occupied by an object of type TYPE
when it resides in memory. The value is measured in units of bytes,
value was computed on both sides of the jump. So make sure it isn't
eliminated as dead. */
TREE_SIDE_EFFECTS (t) = 1;
+ TREE_READONLY (t) = 1;
return t;
}
case GOTO_SUBROUTINE_EXPR:
case RTL_EXPR:
return 0;
- case CALL_EXPR:
- return 2;
case WITH_CLEANUP_EXPR:
/* Should be defined to be 2. */
return 1;
abort ();
break;
- case CALL_EXPR:
- CALL_EXPR_RTL (expr) = 0;
- break;
-
default:
if (lang_unsave_expr_now != 0)
(*lang_unsave_expr_now) (expr);
break;
default:
- /* ??? Add a lang hook if it becomes necessary. */
+ if (lang_unsafe_for_reeval != 0)
+ {
+ tmp = (*lang_unsafe_for_reeval) (expr);
+ if (tmp >= 0)
+ return tmp;
+ }
break;
}
if (op0 == TREE_OPERAND (exp, 0))
return exp;
+ if (code == NON_LVALUE_EXPR)
+ return op0;
+
new = fold (build1 (code, TREE_TYPE (exp), op0));
break;
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. */
+ /* Below, we automatically set TREE_SIDE_EFFECTS and TREE_READONLY 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. */
register tree arg0 = va_arg (p, tree);
register tree arg1 = va_arg (p, tree);
+
TREE_OPERAND (t, 0) = arg0;
TREE_OPERAND (t, 1) = arg1;
+ TREE_READONLY (t) = 1;
if (arg0 && fro > 0)
{
if (TREE_SIDE_EFFECTS (arg0))
TREE_SIDE_EFFECTS (t) = 1;
+ if (!TREE_READONLY (arg0))
+ TREE_READONLY (t) = 0;
}
+
if (arg1 && fro > 1)
{
if (TREE_SIDE_EFFECTS (arg1))
TREE_SIDE_EFFECTS (t) = 1;
+ if (!TREE_READONLY (arg1))
+ TREE_READONLY (t) = 0;
}
}
else if (length == 1)
{
register tree arg0 = va_arg (p, tree);
- /* Call build1 for this! */
+ /* The only one-operand cases we handle here are those with side-effects.
+ Others are handled with build1. So don't bother checked if the
+ arg has side-effects since we'll already have set it.
+
+ ??? This really should use build1 too. */
if (TREE_CODE_CLASS (code) != 's')
abort ();
TREE_OPERAND (t, 0) = arg0;
- if (fro > 0)
- {
- if (arg0 && TREE_SIDE_EFFECTS (arg0))
- TREE_SIDE_EFFECTS (t) = 1;
- }
}
else
{
for (i = 0; i < length; i++)
{
register tree operand = va_arg (p, tree);
+
TREE_OPERAND (t, i) = operand;
if (operand && fro > i)
{
tree type;
tree node;
{
- register struct obstack *obstack = expression_obstack;
register int length;
#ifdef GATHER_STATISTICS
register tree_node_kind kind;
length = sizeof (struct tree_exp);
- if (ggc_p)
- t = ggc_alloc_tree (length);
- else
- t = (tree) obstack_alloc (obstack, length);
+ t = ggc_alloc_tree (length);
memset ((PTR) t, 0, sizeof (struct tree_common));
#endif
TREE_SET_CODE (t, code);
- TREE_SET_PERMANENT (t);
TREE_TYPE (t) = type;
TREE_COMPLEXITY (t) = 0;
TREE_OPERAND (t, 0) = node;
- if (node && first_rtl_op (code) != 0 && TREE_SIDE_EFFECTS (node))
- TREE_SIDE_EFFECTS (t) = 1;
+ if (node && first_rtl_op (code) != 0)
+ {
+ TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (node);
+ TREE_READONLY (t) = TREE_READONLY (node);
+ }
switch (code)
{
/* All of these have side-effects, no matter what their
operands are. */
TREE_SIDE_EFFECTS (t) = 1;
+ TREE_READONLY (t) = 0;
break;
default:
#ifndef ANSI_PROTOTYPES
enum tree_code code;
#endif
- register struct obstack *ambient_obstack = expression_obstack;
va_list p;
register tree t;
register int length;
code = va_arg (p, enum tree_code);
#endif
- expression_obstack = &temp_decl_obstack;
-
t = make_node (code);
length = TREE_CODE_LENGTH (code);
TREE_OPERAND (t, i) = va_arg (p, tree);
va_end (p);
- expression_obstack = ambient_obstack;
return t;
}
unsigned int hashcode;
tree ntype;
- push_obstacks (TYPE_OBSTACK (ttype), TYPE_OBSTACK (ttype));
ntype = copy_node (ttype);
TYPE_POINTER_TO (ntype) = 0;
ntype = type_hash_canon (hashcode, ntype);
ttype = build_qualified_type (ntype, TYPE_QUALS (ttype));
- pop_obstacks ();
}
return ttype;
tree type;
{
register tree t, m = TYPE_MAIN_VARIANT (type);
- register struct obstack *ambient_obstack = current_obstack;
- current_obstack = TYPE_OBSTACK (type);
t = copy_node (type);
- current_obstack = ambient_obstack;
TYPE_POINTER_TO (t) = 0;
TYPE_REFERENCE_TO (t) = 0;
t1 = type_hash_lookup (hashcode, type);
if (t1 != 0)
{
- 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);
}
/* If this is a permanent type, record it for later reuse. */
- if (ggc_p || TREE_PERMANENT (type))
- type_hash_add (hashcode, type);
+ type_hash_add (hashcode, type);
return type;
}
htab_traverse (t, mark_hash_entry, 0);
}
+/* Mark the hashtable slot pointed to by ENTRY (which is really a
+ `tree**') for GC. */
+
+static int
+mark_tree_hashtable_entry (entry, data)
+ void **entry;
+ void *data ATTRIBUTE_UNUSED;
+{
+ ggc_mark_tree ((tree) *entry);
+ return 1;
+}
+
+/* Mark ARG (which is really a htab_t whose slots are trees) for
+ GC. */
+
+void
+mark_tree_hashtable (arg)
+ void *arg;
+{
+ htab_t t = *(htab_t *) arg;
+ htab_traverse (t, mark_tree_hashtable_entry, 0);
+}
+
static void
print_type_hash_statistics ()
{
case STRING_CST:
return (TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2)
- && ! bcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
+ && ! memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
TREE_STRING_LENGTH (t1)));
case CONSTRUCTOR:
if (t != 0)
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));
+ /* We need a new one. */
t = make_node (POINTER_TYPE);
- pop_obstacks ();
TREE_TYPE (t) = to_type;
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));
+ /* We need a new one. */
t = make_node (REFERENCE_TYPE);
- pop_obstacks ();
TREE_TYPE (t) = to_type;
return t;
}
+/* Build a type that is compatible with t but has no cv quals anywhere
+ in its type, thus
+
+ const char *const *const * -> char ***. */
+
+tree
+build_type_no_quals (t)
+ tree t;
+{
+ switch (TREE_CODE (t))
+ {
+ case POINTER_TYPE:
+ return build_pointer_type (build_type_no_quals (TREE_TYPE (t)));
+ case REFERENCE_TYPE:
+ return build_reference_type (build_type_no_quals (TREE_TYPE (t)));
+ default:
+ return TYPE_MAIN_VARIANT (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).
TREE_TYPE (itype) = sizetype;
TYPE_PRECISION (itype) = TYPE_PRECISION (sizetype);
TYPE_MIN_VALUE (itype) = size_zero_node;
-
- push_obstacks (TYPE_OBSTACK (itype), TYPE_OBSTACK (itype));
TYPE_MAX_VALUE (itype) = convert (sizetype, maxval);
- pop_obstacks ();
-
TYPE_MODE (itype) = TYPE_MODE (sizetype);
TYPE_SIZE (itype) = TYPE_SIZE (sizetype);
TYPE_SIZE_UNIT (itype) = TYPE_SIZE_UNIT (sizetype);
if (type == NULL_TREE)
type = sizetype;
- push_obstacks (TYPE_OBSTACK (itype), TYPE_OBSTACK (itype));
TYPE_MIN_VALUE (itype) = convert (type, lowval);
TYPE_MAX_VALUE (itype) = highval ? convert (type, highval) : NULL;
- pop_obstacks ();
TYPE_PRECISION (itype) = TYPE_PRECISION (type);
TYPE_MODE (itype) = TYPE_MODE (type);
/* Since type_for_size always gives an integer type. */
&& TREE_CODE (type) != REAL_TYPE
/* Don't crash if field not laid out yet. */
- && DECL_SIZE (TREE_OPERAND (op, 1)) != 0)
+ && DECL_SIZE (TREE_OPERAND (op, 1)) != 0
+ && host_integerp (DECL_SIZE (TREE_OPERAND (op, 1)), 1))
{
unsigned int innerprec
- = TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (op, 1)));
+ = tree_low_cst (DECL_SIZE (TREE_OPERAND (op, 1)), 1);
type = type_for_size (innerprec, TREE_UNSIGNED (TREE_OPERAND (op, 1)));
TREE_THIS_VOLATILE (win) = TREE_THIS_VOLATILE (op);
}
}
+
return win;
}
\f
int_fits_type_p (c, type)
tree c, type;
{
- if (TREE_UNSIGNED (type))
- return (! (TREE_CODE (TYPE_MAX_VALUE (type)) == INTEGER_CST
- && INT_CST_LT_UNSIGNED (TYPE_MAX_VALUE (type), c))
- && ! (TREE_CODE (TYPE_MIN_VALUE (type)) == INTEGER_CST
- && INT_CST_LT_UNSIGNED (c, TYPE_MIN_VALUE (type)))
- /* Negative ints never fit unsigned types. */
- && ! (TREE_INT_CST_HIGH (c) < 0
- && ! TREE_UNSIGNED (TREE_TYPE (c))));
+ /* If the bounds of the type are integers, we can check ourselves.
+ Otherwise,. use force_fit_type, which checks against the precision. */
+ if (TYPE_MAX_VALUE (type) != NULL_TREE
+ && TYPE_MIN_VALUE (type) != NULL_TREE
+ && TREE_CODE (TYPE_MAX_VALUE (type)) == INTEGER_CST
+ && TREE_CODE (TYPE_MIN_VALUE (type)) == INTEGER_CST)
+ {
+ if (TREE_UNSIGNED (type))
+ return (! INT_CST_LT_UNSIGNED (TYPE_MAX_VALUE (type), c)
+ && ! INT_CST_LT_UNSIGNED (c, TYPE_MIN_VALUE (type))
+ /* Negative ints never fit unsigned types. */
+ && ! (TREE_INT_CST_HIGH (c) < 0
+ && ! TREE_UNSIGNED (TREE_TYPE (c))));
+ else
+ return (! INT_CST_LT (TYPE_MAX_VALUE (type), c)
+ && ! INT_CST_LT (c, TYPE_MIN_VALUE (type))
+ /* Unsigned ints with top bit set never fit signed types. */
+ && ! (TREE_INT_CST_HIGH (c) < 0
+ && TREE_UNSIGNED (TREE_TYPE (c))));
+ }
else
- return (! (TREE_CODE (TYPE_MAX_VALUE (type)) == INTEGER_CST
- && INT_CST_LT (TYPE_MAX_VALUE (type), c))
- && ! (TREE_CODE (TYPE_MIN_VALUE (type)) == INTEGER_CST
- && INT_CST_LT (c, TYPE_MIN_VALUE (type)))
- /* Unsigned ints with top bit set never fit signed types. */
- && ! (TREE_INT_CST_HIGH (c) < 0
- && TREE_UNSIGNED (TREE_TYPE (c))));
+ {
+ c = copy_node (c);
+ TREE_TYPE (c) = type;
+ return !force_fit_type (c, 0);
+ }
}
/* Given a DECL or TYPE, return the scope in which it was declared, or
fprintf (stderr, "(No per-node statistics)\n");
#endif
print_obstack_statistics ("permanent_obstack", &permanent_obstack);
- print_obstack_statistics ("maybepermanent_obstack", &maybepermanent_obstack);
- print_obstack_statistics ("temporary_obstack", &temporary_obstack);
- print_obstack_statistics ("momentary_obstack", &momentary_obstack);
- print_obstack_statistics ("temp_decl_obstack", &temp_decl_obstack);
print_type_hash_statistics ();
print_lang_statistics ();
}
#ifdef BUILD_VA_LIST_TYPE
BUILD_VA_LIST_TYPE (va_list_type_node);
#else
- va_list_type_node = ptr_type_node;
+ va_list_type_node = build_type_copy (ptr_type_node);
#endif
V4SF_type_node = make_node (VECTOR_TYPE);