X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftree.c;h=acc744619b3a625d28379ac0768940477acbd0a2;hb=fd944c82b484fee0514fefed73ce1622127976cc;hp=fab3d1de0c9c0eb76dbd677c4c99645e61c1541b;hpb=9965111454e04d976fa6a49de3c21eeee34c33cc;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/tree.c b/gcc/tree.c index fab3d1de0c9..acc744619b3 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -53,112 +53,10 @@ 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 - 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. */ @@ -233,14 +131,6 @@ static const char * const tree_node_kind_names[] = { "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. */ @@ -280,6 +170,7 @@ 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)); +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 @@ -289,12 +180,9 @@ static void finish_vector_type PARAMS((tree)); 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 ("") +/* 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)); tree global_trees[TI_MAX]; tree integer_types[itk_none]; @@ -304,30 +192,8 @@ 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); @@ -356,309 +222,7 @@ gcc_obstack_init (obstack) (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; -} -/* 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; -} - -/* 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. */ @@ -679,220 +243,10 @@ perm_calloc (nelem, size) 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); -} - -/* 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); -} - -/* 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; -} - -/* 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 @@ -951,9 +305,6 @@ tree_size (node) } /* 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. @@ -1037,7 +388,6 @@ make_node (code) memset ((PTR) t, 0, length); TREE_SET_CODE (t, code); - TREE_SET_PERMANENT (t); switch (type) { @@ -1053,7 +403,7 @@ make_node (code) 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 : ""; DECL_UID (t) = next_decl_uid++; /* Note that we have not yet computed the alias set for this declaration. */ @@ -1062,7 +412,7 @@ make_node (code) 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; @@ -1133,10 +483,7 @@ copy_node (node) 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; @@ -1147,8 +494,6 @@ copy_node (node) 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 @@ -1158,8 +503,6 @@ copy_node (node) TYPE_SYMTAB_ADDRESS (t) = 0; } - TREE_SET_PERMANENT (t); - return t; } @@ -1186,136 +529,7 @@ copy_list (list) } return head; } - -#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); -} /* Return a newly constructed INTEGER_CST node whose constant value is specified by the two ints LOW and HI. @@ -1373,7 +587,7 @@ real_value_from_int_cst (type, i) #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), @@ -1492,17 +706,10 @@ build_string (len, str) 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; } @@ -1536,22 +743,17 @@ make_tree_vec (len) { 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; } @@ -2062,36 +1264,6 @@ build_tree_list (parm, value) 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. */ @@ -2102,10 +1274,7 @@ tree_cons (purpose, value, 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)); @@ -2115,88 +1284,12 @@ tree_cons (purpose, value, chain) #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; -} /* Return the size nominally occupied by an object of type TYPE when it resides in memory. The value is measured in units of bytes, @@ -2482,6 +1575,7 @@ save_expr (expr) 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; } @@ -2518,8 +1612,6 @@ first_rtl_op (code) 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; @@ -2562,10 +1654,6 @@ unsave_expr_1 (expr) abort (); break; - case CALL_EXPR: - CALL_EXPR_RTL (expr) = 0; - break; - default: if (lang_unsave_expr_now != 0) (*lang_unsave_expr_now) (expr); @@ -2694,7 +1782,12 @@ unsafe_for_reeval (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; } @@ -2928,6 +2021,9 @@ substitute_in_expr (exp, f, r) if (op0 == TREE_OPERAND (exp, 0)) return exp; + if (code == NON_LVALUE_EXPR) + return op0; + new = fold (build1 (code, TREE_TYPE (exp), op0)); break; @@ -3243,10 +2339,10 @@ build VPARAMS ((enum tree_code code, tree tt, ...)) 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) @@ -3254,38 +2350,45 @@ build VPARAMS ((enum tree_code code, tree tt, ...)) /* 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) { @@ -3308,7 +2411,6 @@ build1 (code, type, node) tree type; tree node; { - register struct obstack *obstack = expression_obstack; register int length; #ifdef GATHER_STATISTICS register tree_node_kind kind; @@ -3324,10 +2426,7 @@ build1 (code, type, node) 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)); @@ -3337,13 +2436,15 @@ build1 (code, type, node) #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) { @@ -3358,6 +2459,7 @@ build1 (code, type, node) /* All of these have side-effects, no matter what their operands are. */ TREE_SIDE_EFFECTS (t) = 1; + TREE_READONLY (t) = 0; break; default: @@ -3408,7 +2510,6 @@ build_parse_node VPARAMS ((enum tree_code code, ...)) #ifndef ANSI_PROTOTYPES enum tree_code code; #endif - register struct obstack *ambient_obstack = expression_obstack; va_list p; register tree t; register int length; @@ -3420,8 +2521,6 @@ build_parse_node VPARAMS ((enum tree_code code, ...)) code = va_arg (p, enum tree_code); #endif - expression_obstack = &temp_decl_obstack; - t = make_node (code); length = TREE_CODE_LENGTH (code); @@ -3429,7 +2528,6 @@ build_parse_node VPARAMS ((enum tree_code code, ...)) TREE_OPERAND (t, i) = va_arg (p, tree); va_end (p); - expression_obstack = ambient_obstack; return t; } @@ -3554,7 +2652,6 @@ build_type_attribute_variant (ttype, attribute) unsigned int hashcode; tree ntype; - push_obstacks (TYPE_OBSTACK (ttype), TYPE_OBSTACK (ttype)); ntype = copy_node (ttype); TYPE_POINTER_TO (ntype) = 0; @@ -3590,7 +2687,6 @@ build_type_attribute_variant (ttype, attribute) ntype = type_hash_canon (hashcode, ntype); ttype = build_qualified_type (ntype, TYPE_QUALS (ttype)); - pop_obstacks (); } return ttype; @@ -3906,11 +3002,8 @@ build_type_copy (type) 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; @@ -4053,9 +3146,6 @@ type_hash_canon (hashcode, type) 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); @@ -4064,8 +3154,7 @@ type_hash_canon (hashcode, 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; } @@ -4096,6 +3185,29 @@ mark_type_hash (arg) 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 () { @@ -4389,7 +3501,7 @@ simple_cst_equal (t1, t2) 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: @@ -4520,10 +3632,8 @@ build_pointer_type (to_type) 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; @@ -4551,10 +3661,8 @@ build_reference_type (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; @@ -4566,6 +3674,26 @@ build_reference_type (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). @@ -4584,11 +3712,7 @@ build_index_type (maxval) 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); @@ -4616,10 +3740,8 @@ build_range_type (type, lowval, highval) 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); @@ -4969,10 +4091,11 @@ get_unwidened (op, for_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))); @@ -4994,6 +4117,7 @@ get_unwidened (op, for_type) TREE_THIS_VOLATILE (win) = TREE_THIS_VOLATILE (op); } } + return win; } @@ -5092,22 +4216,32 @@ int 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 @@ -5281,10 +4415,6 @@ dump_tree_statistics () 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 (); } @@ -5709,7 +4839,7 @@ build_common_tree_nodes_2 (short_double) #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);