/* Language-independent node constructors for parse phase of GNU compiler.
- Copyright (C) 1987, 88, 92-97, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 92-98, 1999 Free Software Foundation, Inc.
This file is part of GNU CC.
#include "config.h"
#include "system.h"
-#include <setjmp.h>
#include "flags.h"
#include "tree.h"
-#include "except.h"
+#include "tm_p.h"
#include "function.h"
#include "obstack.h"
#include "toplev.h"
+#include "ggc.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
/* obstack.[ch] explicitly declined to prototype this. */
-extern int _obstack_allocated_p PROTO ((struct obstack *h, GENERIC_PTR obj));
+extern int _obstack_allocated_p PROTO ((struct obstack *h, PTR obj));
/* Tree nodes of permanent duration are allocated in this obstack.
They are the identifier nodes, and everything outside of
struct obstack maybepermanent_obstack;
-/* This is a list of function_maybepermanent_obstacks for top-level inline
- functions that are compiled in the middle of compiling other functions. */
-
-struct simple_obstack_stack *toplev_inline_obstacks;
-
-/* Former elements of toplev_inline_obstacks that have been recycled. */
-
-struct simple_obstack_stack *extra_inline_obstacks;
-
-/* This is a list of function_maybepermanent_obstacks for inline functions
- nested in the current function that were compiled in the middle of
- compiling other functions. */
-
-struct simple_obstack_stack *inline_obstacks;
-
/* The contents of the current function definition are allocated
in this obstack, and all are freed at the end of the function.
For top-level functions, this is temporary_obstack.
Used for printing out the tree and error messages. */
#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
-char *tree_code_name[MAX_TREE_CODES] = {
+const char *tree_code_name[MAX_TREE_CODES] = {
#include "tree.def"
};
#undef DEFTREECODE
int tree_node_sizes[(int)all_kinds];
int id_string_size = 0;
-char *tree_node_kind_names[] = {
+static const char * const tree_node_kind_names[] = {
"decls",
"types",
"blocks",
codes are made. */
#define TYPE_HASH(TYPE) ((unsigned long) (TYPE) & 0777777)
+/* Each hash table slot is a bucket containing a chain
+ of these structures. */
+
+struct type_hash
+{
+ struct type_hash *next; /* Next structure in the bucket. */
+ int hashcode; /* Hash code of this type. */
+ tree type; /* The type recorded here. */
+};
+
+/* Now here is the hash table. When recording a type, it is added
+ to the slot whose index is the hash code mod the table size.
+ Note that the hash table is used for several kinds of types
+ (function types, array types and array index range types, for now).
+ While all these live in the same table, they are completely independent,
+ and the hash code is computed differently for each of these. */
+
+#define TYPE_HASH_SIZE 59
+struct type_hash *type_hash_table[TYPE_HASH_SIZE];
+
static void set_type_quals PROTO((tree, int));
static void append_random_chars PROTO((char *));
+static void build_real_from_int_cst_1 PROTO((PTR));
+static void mark_type_hash PROTO ((void *));
+static void fix_sizetype PROTO ((tree));
+
+/* If non-null, a language specific helper for unsave_expr_now. */
-extern char *mode_name[];
+void (*lang_unsave_expr_now) PROTO((tree));
-void gcc_obstack_init ();
+/* The string used as a placeholder instead of a source file name for
+ built-in tree nodes. The variable, which is dynamically allocated,
+ should be used; the macro is only used to initialize it. */
+
+static char *built_in_filename;
+#define BUILT_IN_FILENAME ("<built-in>")
+\f
+tree global_trees[TI_MAX];
\f
/* Init the principal obstacks. */
/* Init the hash table of identifiers. */
bzero ((char *) hash_table, sizeof hash_table);
+
+ ggc_add_tree_root (hash_table, MAX_HASH_TABLE);
+ ggc_add_root (type_hash_table, TYPE_HASH_SIZE,
+ sizeof(struct type_hash *),
+ mark_type_hash);
+ ggc_add_tree_root (global_trees, TI_MAX);
}
void
#define OBSTACK_CHUNK_FREE free
#endif
_obstack_begin (obstack, OBSTACK_CHUNK_SIZE, 0,
- (void *(*) ()) OBSTACK_CHUNK_ALLOC,
- (void (*) ()) OBSTACK_CHUNK_FREE);
+ (void *(*) PROTO ((long))) OBSTACK_CHUNK_ALLOC,
+ (void (*) PROTO ((void *))) OBSTACK_CHUNK_FREE);
}
-/* Save all variables describing the current status into the structure *P.
- This is used before starting a nested function.
+/* 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, context)
+save_tree_status (p)
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;
-
- 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;
- }
-
- if (context == NULL_TREE && extra_inline_obstacks)
- {
- current = extra_inline_obstacks;
- extra_inline_obstacks = current->next;
- }
- else
- {
- current = ((struct simple_obstack_stack *)
- xmalloc (sizeof (struct simple_obstack_stack)));
-
- current->obstack
- = (struct obstack *) xmalloc (sizeof (struct obstack));
- gcc_obstack_init (current->obstack);
- }
-
- function_maybepermanent_obstack = current->obstack;
-
- current->next = *head;
- *head = current;
- }
+ function_maybepermanent_obstack
+ = (struct obstack *) xmalloc (sizeof (struct obstack));
+ gcc_obstack_init (function_maybepermanent_obstack);
maybepermanent_firstobj
= (char *) obstack_finish (function_maybepermanent_obstack);
This is used after a nested function. */
void
-restore_tree_status (p, context)
+restore_tree_status (p)
struct function *p;
- tree context;
{
all_types_permanent = p->all_types_permanent;
momentary_stack = p->momentary_stack;
obstack_free (&momentary_obstack, momentary_function_firstobj);
/* Free saveable storage used by the function just compiled and not
- saved.
-
- CAUTION: This is in function_obstack of the containing function.
- So we must be sure that we never allocate from that obstack during
- the compilation of a nested function if we expect it to survive
- past the nested function's end. */
+ saved. */
obstack_free (function_maybepermanent_obstack, maybepermanent_firstobj);
-
- /* If we were compiling a toplevel function, we can free this space now. */
- if (context == NULL_TREE)
+ if (obstack_empty_p (function_maybepermanent_obstack))
{
- obstack_free (&temporary_obstack, temporary_firstobj);
- obstack_free (&momentary_obstack, momentary_function_firstobj);
+ obstack_free (function_maybepermanent_obstack, NULL);
+ free (function_maybepermanent_obstack);
}
- /* If we were compiling a toplevel function that we don't actually want
- to save anything from, return the obstack to the pool. */
- if (context == NULL_TREE
- && obstack_empty_p (function_maybepermanent_obstack))
- {
- struct simple_obstack_stack *current, **p = &toplev_inline_obstacks;
-
- if ((*p) != NULL)
- {
- while ((*p)->obstack != function_maybepermanent_obstack)
- p = &((*p)->next);
- current = *p;
- *p = current->next;
-
- current->next = extra_inline_obstacks;
- extra_inline_obstacks = current;
- }
- }
+ obstack_free (&temporary_obstack, temporary_firstobj);
+ obstack_free (&momentary_obstack, momentary_function_firstobj);
- obstack_free (function_obstack, 0);
+ obstack_free (function_obstack, NULL);
free (function_obstack);
temporary_firstobj = p->temporary_firstobj;
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
push_obstacks (current, saveable)
struct obstack *current, *saveable;
{
- struct obstack_stack *p
- = (struct obstack_stack *) obstack_alloc (&obstack_stack_obstack,
+ struct obstack_stack *p;
+
+ p = (struct obstack_stack *) obstack_alloc (&obstack_stack_obstack,
(sizeof (struct obstack_stack)));
p->current = current_obstack;
void
push_obstacks_nochange ()
{
- struct obstack_stack *p
- = (struct obstack_stack *) obstack_alloc (&obstack_stack_obstack,
+ struct obstack_stack *p;
+
+ p = (struct obstack_stack *) obstack_alloc (&obstack_stack_obstack,
(sizeof (struct obstack_stack)));
p->current = current_obstack;
void
pop_obstacks ()
{
- struct obstack_stack *p = obstack_stack;
+ struct obstack_stack *p;
+
+ p = obstack_stack;
obstack_stack = p->next;
current_obstack = p->current;
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;
print_obstack_name (object, file, prefix)
char *object;
FILE *file;
- char *prefix;
+ const char *prefix;
{
struct obstack *obstack = NULL;
- char *obstack_name = NULL;
+ const char *obstack_name = NULL;
struct function *p;
for (p = outer_function_chain; p; p = p->next)
void
init_tree_codes ()
{
-
+ built_in_filename =
+ ggc_alloc_string (BUILT_IN_FILENAME, sizeof (BUILT_IN_FILENAME));
+ ggc_add_string_root (&built_in_filename, 1);
}
/* Return a newly allocated node of code CODE.
register int type = TREE_CODE_CLASS (code);
register int length = 0;
register struct obstack *obstack = current_obstack;
- register int i;
#ifdef GATHER_STATISTICS
register tree_node_kind kind;
#endif
abort ();
}
- t = (tree) obstack_alloc (obstack, length);
- bzero (t, length);
+ if (ggc_p)
+ t = ggc_alloc_tree (length);
+ else
+ {
+ t = (tree) obstack_alloc (obstack, length);
+ memset ((PTR) t, 0, length);
+ }
#ifdef GATHER_STATISTICS
tree_node_counts[(int)kind]++;
DECL_IN_SYSTEM_HEADER (t)
= in_system_header && (obstack == &permanent_obstack);
DECL_SOURCE_LINE (t) = lineno;
- DECL_SOURCE_FILE (t) = (input_filename) ? input_filename : "<built-in>";
+ DECL_SOURCE_FILE (t) =
+ (input_filename) ? input_filename : built_in_filename;
DECL_UID (t) = next_decl_uid++;
/* Note that we have not yet computed the alias set for this
declaration. */
case 'c':
TREE_CONSTANT (t) = 1;
break;
+
+ case 'e':
+ switch (code)
+ {
+ case INIT_EXPR:
+ case MODIFY_EXPR:
+ case VA_ARG_EXPR:
+ case RTL_EXPR:
+ case PREDECREMENT_EXPR:
+ case PREINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ /* All of these have side-effects, no matter what their
+ operands are. */
+ TREE_SIDE_EFFECTS (t) = 1;
+ break;
+
+ default:
+ break;
+ }
+ break;
}
return t;
}
+
+/* A front-end can reset this to an appropriate function if types need
+ special handling. */
+
+tree (*make_lang_type_fn) PROTO((enum tree_code)) = make_node;
+
+/* Return a new type (with the indicated CODE), doing whatever
+ language-specific processing is required. */
+
+tree
+make_lang_type (code)
+ enum tree_code code;
+{
+ return (*make_lang_type_fn) (code);
+}
\f
-/* Return a new node with the same contents as NODE
- except that its TREE_CHAIN is zero and it has a fresh uid. */
+/* Return a new node with the same contents as NODE except that its
+ TREE_CHAIN is zero and it has a fresh uid. Unlike make_node, this
+ function always performs the allocation on the CURRENT_OBSTACK;
+ it's up to the caller to pick the right obstack before calling this
+ function. */
tree
copy_node (node)
register tree t;
register enum tree_code code = TREE_CODE (node);
register int length = 0;
- register int i;
switch (TREE_CODE_CLASS (code))
{
length += (TREE_VEC_LENGTH (node) - 1) * sizeof (char *);
}
- t = (tree) obstack_alloc (current_obstack, length);
- bzero (t, length);
+ if (ggc_p)
+ t = ggc_alloc_tree (length);
+ else
+ t = (tree) obstack_alloc (current_obstack, length);
+ memcpy (t, node, length);
/* EXPR_WITH_FILE_LOCATION must keep filename info stored in TREE_CHAIN */
if (TREE_CODE (node) != EXPR_WITH_FILE_LOCATION)
tree
get_identifier (text)
- register char *text;
+ register const char *text;
{
register int hi;
register int i;
id_string_size += len;
#endif
- IDENTIFIER_POINTER (idp) = obstack_copy0 (&permanent_obstack, text, len);
+ if (ggc_p)
+ IDENTIFIER_POINTER (idp) = ggc_alloc_string (text, len);
+ else
+ IDENTIFIER_POINTER (idp) = obstack_copy0 (&permanent_obstack, text, len);
TREE_CHAIN (idp) = hash_table[hi];
hash_table[hi] = idp;
tree
maybe_get_identifier (text)
- register char *text;
+ register const char *text;
{
register int hi;
register int i;
return d;
}
+struct brfic_args
+{
+ /* Input */
+ tree type, i;
+ /* Output */
+ REAL_VALUE_TYPE d;
+};
+
+static void
+build_real_from_int_cst_1 (data)
+ PTR data;
+{
+ struct brfic_args * args = (struct brfic_args *) data;
+
+#ifdef REAL_ARITHMETIC
+ args->d = real_value_from_int_cst (args->type, args->i);
+#else
+ args->d =
+ REAL_VALUE_TRUNCATE (TYPE_MODE (args->type),
+ real_value_from_int_cst (args->type, args->i));
+#endif
+}
+
/* This function can't be implemented if we can't do arithmetic
on the float representation. */
tree v;
int overflow = TREE_OVERFLOW (i);
REAL_VALUE_TYPE d;
- jmp_buf float_error;
+ struct brfic_args args;
v = make_node (REAL_CST);
TREE_TYPE (v) = type;
- if (setjmp (float_error))
+ /* Setup input for build_real_from_int_cst_1() */
+ args.type = type;
+ args.i = i;
+
+ if (do_float_handler (build_real_from_int_cst_1, (PTR) &args))
{
+ /* Receive output from build_real_from_int_cst_1() */
+ d = args.d;
+ }
+ else
+ {
+ /* We got an exception from build_real_from_int_cst_1() */
d = dconst0;
overflow = 1;
- goto got_it;
}
-
- set_float_handler (float_error);
-
-#ifdef REAL_ARITHMETIC
- d = real_value_from_int_cst (type, i);
-#else
- d = REAL_VALUE_TRUNCATE (TYPE_MODE (type),
- real_value_from_int_cst (type, i));
-#endif
-
+
/* Check for valid float value for this type on this target machine. */
- got_it:
- set_float_handler (NULL_PTR);
-
#ifdef CHECK_FLOAT_VALUE
CHECK_FLOAT_VALUE (TYPE_MODE (type), d, overflow);
#endif
tree
build_string (len, str)
int len;
- char *str;
+ 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
register tree s = make_node (STRING_CST);
TREE_STRING_LENGTH (s) = len;
- TREE_STRING_POINTER (s) = obstack_copy0 (saveable_obstack, str, len);
+ if (ggc_p)
+ TREE_STRING_POINTER (s) = ggc_alloc_string (str, len);
+ else
+ TREE_STRING_POINTER (s) = obstack_copy0 (saveable_obstack, str, len);
return s;
}
register tree t;
register int length = (len-1) * sizeof (tree) + sizeof (struct tree_vec);
register struct obstack *obstack = current_obstack;
- register int i;
#ifdef GATHER_STATISTICS
tree_node_counts[(int)vec_kind]++;
tree_node_sizes[(int)vec_kind] += length;
#endif
- t = (tree) obstack_alloc (obstack, length);
- bzero (t, length);
+ if (ggc_p)
+ t = ggc_alloc_tree (length);
+ else
+ {
+ t = (tree) obstack_alloc (obstack, length);
+ bzero ((PTR) t, length);
+ }
TREE_SET_CODE (t, TREE_VEC);
TREE_VEC_LENGTH (t) = len;
if (op1)
{
register tree t1;
+#ifdef ENABLE_CHECKING
register tree t2;
+#endif
for (t1 = op1; TREE_CHAIN (t1); t1 = TREE_CHAIN (t1))
;
TREE_CHAIN (t1) = op2;
+#ifdef ENABLE_CHECKING
for (t2 = op2; t2; t2 = TREE_CHAIN (t2))
if (t2 == t1)
abort (); /* Circularity created. */
+#endif
return op1;
}
else return op2;
#if 0
register tree node = make_node (TREE_LIST);
#else
- register int i;
- register tree node = (tree) obstack_alloc (current_obstack, sizeof (struct tree_list));
+ register tree node;
+
+ if (ggc_p)
+ node = ggc_alloc_tree (sizeof (struct tree_list));
+ else
+ {
+ node = (tree) obstack_alloc (current_obstack, sizeof (struct tree_list));
+ memset (node, 0, sizeof (struct tree_common));
+ }
+
#ifdef GATHER_STATISTICS
tree_node_counts[(int)x_kind]++;
tree_node_sizes[(int)x_kind] += sizeof (struct tree_list);
#endif
- for (i = (sizeof (struct tree_common) / sizeof (int)) - 1; i >= 0; i--)
- ((int *) node)[i] = 0;
TREE_SET_CODE (node, TREE_LIST);
if (current_obstack == &permanent_obstack)
if (! TREE_CONSTANT (min))
{
STRIP_NOPS (min);
- if (TREE_CODE (min) == SAVE_EXPR)
+ if (TREE_CODE (min) == SAVE_EXPR && SAVE_EXPR_RTL (min))
min = build (RTL_EXPR, TREE_TYPE (TYPE_MIN_VALUE (index_type)), 0,
SAVE_EXPR_RTL (min));
else
if (! TREE_CONSTANT (max))
{
STRIP_NOPS (max);
- if (TREE_CODE (max) == SAVE_EXPR)
+ if (TREE_CODE (max) == SAVE_EXPR && SAVE_EXPR_RTL (max))
max = build (RTL_EXPR, TREE_TYPE (TYPE_MAX_VALUE (index_type)), 0,
SAVE_EXPR_RTL (max));
else
{
case SAVE_EXPR:
return 2;
+ case GOTO_SUBROUTINE_EXPR:
case RTL_EXPR:
return 0;
case CALL_EXPR:
}
/* Modify a tree in place so that all the evaluate only once things
- are cleared out. Return the EXPR given. */
+ are cleared out. Return the EXPR given.
+
+ LANG_UNSAVE_EXPR_NOW, if set, is a pointer to a function to handle
+ language specific nodes.
+*/
tree
unsave_expr_now (expr)
break;
default:
+ if (lang_unsave_expr_now)
+ (*lang_unsave_expr_now) (expr);
break;
}
switch (TREE_CODE (exp))
{
case TARGET_EXPR:
+ case GOTO_SUBROUTINE_EXPR:
case WITH_CLEANUP_EXPR:
return 1;
register tree t;
register int length;
register int i;
+ int fro;
VA_START (p, tt);
length = tree_code_length[(int) code];
TREE_TYPE (t) = tt;
+ /* Below, we automatically set TREE_SIDE_EFFECTS and TREE_RAISED for
+ the result based on those same flags for the arguments. But, if
+ the arguments aren't really even `tree' expressions, we shouldn't
+ be trying to do this. */
+ fro = first_rtl_op (code);
+
if (length == 2)
{
/* This is equivalent to the loop below, but faster. */
register tree arg1 = va_arg (p, tree);
TREE_OPERAND (t, 0) = arg0;
TREE_OPERAND (t, 1) = arg1;
- if ((arg0 && TREE_SIDE_EFFECTS (arg0))
- || (arg1 && TREE_SIDE_EFFECTS (arg1)))
- TREE_SIDE_EFFECTS (t) = 1;
- TREE_RAISES (t)
- = (arg0 && TREE_RAISES (arg0)) || (arg1 && TREE_RAISES (arg1));
+ if (arg0 && fro > 0)
+ {
+ if (TREE_SIDE_EFFECTS (arg0))
+ TREE_SIDE_EFFECTS (t) = 1;
+ if (TREE_RAISES (arg0))
+ TREE_RAISES (t) = 1;
+ }
+ if (arg1 && fro > 1)
+ {
+ if (TREE_SIDE_EFFECTS (arg1))
+ TREE_SIDE_EFFECTS (t) = 1;
+ if (TREE_RAISES (arg1))
+ TREE_RAISES (t) = 1;
+ }
}
else if (length == 1)
{
if (TREE_CODE_CLASS (code) != 's')
abort ();
TREE_OPERAND (t, 0) = arg0;
- if (arg0 && TREE_SIDE_EFFECTS (arg0))
- TREE_SIDE_EFFECTS (t) = 1;
- TREE_RAISES (t) = (arg0 && TREE_RAISES (arg0));
+ if (fro > 0)
+ {
+ if (arg0 && TREE_SIDE_EFFECTS (arg0))
+ TREE_SIDE_EFFECTS (t) = 1;
+ TREE_RAISES (t) = (arg0 && TREE_RAISES (arg0));
+ }
}
else
{
{
register tree operand = va_arg (p, tree);
TREE_OPERAND (t, i) = operand;
- if (operand)
+ if (operand && fro > i)
{
if (TREE_SIDE_EFFECTS (operand))
TREE_SIDE_EFFECTS (t) = 1;
tree node;
{
register struct obstack *obstack = expression_obstack;
- register int i, length;
+ register int length;
#ifdef GATHER_STATISTICS
register tree_node_kind kind;
#endif
length = sizeof (struct tree_exp);
- t = (tree) obstack_alloc (obstack, length);
- bzero (t, length);
+ if (ggc_p)
+ t = ggc_alloc_tree (length);
+ else
+ {
+ t = (tree) obstack_alloc (obstack, length);
+ memset ((PTR) t, 0, length);
+ }
#ifdef GATHER_STATISTICS
tree_node_counts[(int)kind]++;
TREE_PERMANENT (t) = 1;
TREE_OPERAND (t, 0) = node;
- if (node)
+ if (node && first_rtl_op (code) != 0)
{
if (TREE_SIDE_EFFECTS (node))
TREE_SIDE_EFFECTS (t) = 1;
TREE_RAISES (t) = 1;
}
+ switch (code)
+ {
+ case INIT_EXPR:
+ case MODIFY_EXPR:
+ case VA_ARG_EXPR:
+ case RTL_EXPR:
+ case PREDECREMENT_EXPR:
+ case PREINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ /* All of these have side-effects, no matter what their
+ operands are. */
+ TREE_SIDE_EFFECTS (t) = 1;
+ break;
+
+ default:
+ break;
+ }
+
return t;
}
{
register tree block = make_node (BLOCK);
BLOCK_VARS (block) = vars;
- BLOCK_TYPE_TAGS (block) = tags;
BLOCK_SUBBLOCKS (block) = subblocks;
BLOCK_SUPERCONTEXT (block) = supercontext;
BLOCK_CHAIN (block) = chain;
tree
build_expr_wfl (node, file, line, col)
tree node;
- char *file;
+ const char *file;
int line, col;
{
- static char *last_file = 0;
+ static const char *last_file = 0;
static tree last_filenode = NULL_TREE;
register tree wfl = make_node (EXPR_WITH_FILE_LOCATION);
current_obstack = TYPE_OBSTACK (ttype);
ntype = copy_node (ttype);
- current_obstack = ambient_obstack;
TYPE_POINTER_TO (ntype) = 0;
TYPE_REFERENCE_TO (ntype) = 0;
ntype = type_hash_canon (hashcode, ntype);
ttype = build_qualified_type (ntype, TYPE_QUALS (ttype));
+
+ /* We must restore the current obstack after the type_hash_canon call,
+ because type_hash_canon calls type_hash_add for permanent types, and
+ then type_hash_add calls oballoc expecting to get something permanent
+ back. */
+ current_obstack = ambient_obstack;
}
return ttype;
tree decl ATTRIBUTE_UNUSED;
tree type ATTRIBUTE_UNUSED;
{
- int valid = 0;
+ int validated = 0;
#ifdef VALID_MACHINE_DECL_ATTRIBUTE
tree decl_attr_list = decl != 0 ? DECL_MACHINE_ATTRIBUTES (decl) : 0;
#endif
decl = build_decl_attribute_variant (decl, decl_attr_list);
}
- valid = 1;
+ validated = 1;
}
#endif
#ifdef VALID_MACHINE_TYPE_ATTRIBUTE
- if (valid)
+ if (validated)
/* Don't apply the attribute to both the decl and the type. */;
else if (VALID_MACHINE_TYPE_ATTRIBUTE (type, type_attr_list, attr_name,
attr_args))
}
if (decl != 0)
TREE_TYPE (decl) = type;
- valid = 1;
+ validated = 1;
}
/* Handle putting a type attribute on pointer-to-function-type by putting
if (decl != 0)
TREE_TYPE (decl) = build_pointer_type (inner_type);
+ else
+ {
+ /* Clear TYPE_POINTER_TO for the old inner type, since
+ `type' won't be pointing to it anymore. */
+ TYPE_POINTER_TO (TREE_TYPE (type)) = NULL_TREE;
+ TREE_TYPE (type) = inner_type;
+ }
- valid = 1;
+ validated = 1;
}
#endif
- return valid;
+ return validated;
}
/* Return non-zero if IDENT is a valid name for attribute ATTR,
int
is_attribute_p (attr, ident)
- char *attr;
+ const char *attr;
tree ident;
{
int ident_len, attr_len;
tree
lookup_attribute (attr_name, list)
- char *attr_name;
+ const char *attr_name;
tree list;
{
tree l;
/* Hashing of types so that we don't make duplicates.
The entry point is `type_hash_canon'. */
-/* Each hash table slot is a bucket containing a chain
- of these structures. */
-
-struct type_hash
-{
- struct type_hash *next; /* Next structure in the bucket. */
- int hashcode; /* Hash code of this type. */
- tree type; /* The type recorded here. */
-};
-
-/* Now here is the hash table. When recording a type, it is added
- to the slot whose index is the hash code mod the table size.
- Note that the hash table is used for several kinds of types
- (function types, array types and array index range types, for now).
- While all these live in the same table, they are completely independent,
- and the hash code is computed differently for each of these. */
-
-#define TYPE_HASH_SIZE 59
-struct type_hash *type_hash_table[TYPE_HASH_SIZE];
-
/* Compute a hash code for a list of types (chain of TREE_LIST nodes
with types in the TREE_VALUE slots), by adding the hash codes
of the individual types. */
tree type;
{
register struct type_hash *h;
+
+ /* The TYPE_ALIGN field of a type is set by layout_type(), so we
+ must call that routine before comparing TYPE_ALIGNs. */
+ layout_type (type);
+
for (h = type_hash_table[hashcode % TYPE_HASH_SIZE]; h; h = h->next)
if (h->hashcode == hashcode
&& TREE_CODE (h->type) == TREE_CODE (type)
&& TREE_TYPE (h->type) == TREE_TYPE (type)
&& attribute_list_equal (TYPE_ATTRIBUTES (h->type),
TYPE_ATTRIBUTES (type))
+ && TYPE_ALIGN (h->type) == TYPE_ALIGN (type)
&& (TYPE_MAX_VALUE (h->type) == TYPE_MAX_VALUE (type)
|| tree_int_cst_equal (TYPE_MAX_VALUE (h->type),
TYPE_MAX_VALUE (type)))
{
register struct type_hash *h;
- h = (struct type_hash *) oballoc (sizeof (struct type_hash));
+ h = (struct type_hash *) permalloc (sizeof (struct type_hash));
h->hashcode = hashcode;
h->type = type;
h->next = type_hash_table[hashcode % TYPE_HASH_SIZE];
t1 = type_hash_lookup (hashcode, type);
if (t1 != 0)
{
- obstack_free (TYPE_OBSTACK (type), type);
+ if (!ggc_p)
+ obstack_free (TYPE_OBSTACK (type), type);
#ifdef GATHER_STATISTICS
tree_node_counts[(int)t_kind]--;
tree_node_sizes[(int)t_kind] -= sizeof (struct tree_type);
}
/* If this is a permanent type, record it for later reuse. */
- if (TREE_PERMANENT (type))
+ if (ggc_p || TREE_PERMANENT (type))
type_hash_add (hashcode, type);
return type;
}
+/* Mark ARG (which is really a struct type_hash **) for GC. */
+
+static void
+mark_type_hash (arg)
+ void *arg;
+{
+ struct type_hash *t = *(struct type_hash **) arg;
+
+ while (t)
+ {
+ ggc_mark_tree (t->type);
+ t = t->next;
+ }
+}
+
/* Compute a hash code for a list of attributes (chain of TREE_LIST nodes
with names in the TREE_PURPOSE slots and args in the TREE_VALUE slots),
by adding the hash codes of the individual attributes. */
if (TYPE_SIZE (t) == 0)
layout_type (t);
+ /* If we are writing Dwarf2 output we need to create a name,
+ since complex is a fundamental type. */
+ if (write_symbols == DWARF2_DEBUG && ! TYPE_NAME (t))
+ {
+ const char *name;
+ if (component_type == char_type_node)
+ name = "complex char";
+ else if (component_type == signed_char_type_node)
+ name = "complex signed char";
+ else if (component_type == unsigned_char_type_node)
+ name = "complex unsigned char";
+ else if (component_type == short_integer_type_node)
+ name = "complex short int";
+ else if (component_type == short_unsigned_type_node)
+ name = "complex short unsigned int";
+ else if (component_type == integer_type_node)
+ name = "complex int";
+ else if (component_type == unsigned_type_node)
+ name = "complex unsigned int";
+ else if (component_type == long_integer_type_node)
+ name = "complex long int";
+ else if (component_type == long_unsigned_type_node)
+ name = "complex long unsigned int";
+ else if (component_type == long_long_integer_type_node)
+ name = "complex long long int";
+ else if (component_type == long_long_unsigned_type_node)
+ name = "complex long long unsigned int";
+ else
+ name = (char *)0;
+
+ if (name)
+ TYPE_NAME (t) = get_identifier (name);
+ }
+
return t;
}
\f
return NULL_TREE;
}
-/* Print debugging information about the size of the
- toplev_inline_obstacks. */
-
-void
-print_inline_obstack_statistics ()
-{
- struct simple_obstack_stack *current = toplev_inline_obstacks;
- int n_obstacks = 0;
- int n_alloc = 0;
- int n_chunks = 0;
-
- for (; current; current = current->next, ++n_obstacks)
- {
- struct obstack *o = current->obstack;
- struct _obstack_chunk *chunk = o->chunk;
-
- n_alloc += o->next_free - chunk->contents;
- chunk = chunk->prev;
- ++n_chunks;
- for (; chunk; chunk = chunk->prev, ++n_chunks)
- n_alloc += chunk->limit - &chunk->contents[0];
- }
- fprintf (stderr, "inline obstacks: %d obstacks, %d bytes, %d chunks\n",
- n_obstacks, n_alloc, n_chunks);
-}
-
/* Print debugging information about the obstack O, named STR. */
void
print_obstack_statistics (str, o)
- char *str;
+ const char *str;
struct obstack *o;
{
struct _obstack_chunk *chunk = o->chunk;
print_obstack_statistics ("temporary_obstack", &temporary_obstack);
print_obstack_statistics ("momentary_obstack", &momentary_obstack);
print_obstack_statistics ("temp_decl_obstack", &temp_decl_obstack);
- print_inline_obstack_statistics ();
print_lang_statistics ();
}
\f
tree
get_file_function_name_long (type)
- char *type;
+ const char *type;
{
char *buf;
register char *p;
/* We don't have anything that we know to be unique to this translation
unit, so use what we do have and throw in some randomness. */
- char *name = weak_global_object_name;
- char *file = main_input_filename;
+ const char *name = weak_global_object_name;
+ const char *file = main_input_filename;
if (! name)
name = "";
if (p != first_global_object_name)
{
for (p = buf+11; *p; p++)
- if (! ((*p >= '0' && *p <= '9')
+ if (! ( ISDIGIT(*p)
#if 0 /* we always want labels, which are valid C++ identifiers (+ `$') */
#ifndef ASM_IDENTIFY_GCC /* this is required if `.' is invalid -- k. raeburn */
|| *p == '.'
#ifndef NO_DOT_IN_LABEL /* this for `.'; unlikely, but... */
|| *p == '.'
#endif
- || (*p >= 'A' && *p <= 'Z')
- || (*p >= 'a' && *p <= 'z')))
+ || ISUPPER(*p)
+ || ISLOWER(*p)))
*p = '_';
}
return non_const_bits;
}
\f
-#ifdef ENABLE_CHECKING
-
-/* Complain if the tree code does not match the expected one.
- NODE is the tree node in question, CODE is the expected tree code,
- and FILE and LINE are the filename and line number, respectively,
- of the line on which the check was done. If NONFATAL is nonzero,
- don't abort if the reference is invalid; instead, return 0.
- If the reference is valid, return NODE. */
-
-tree
-tree_check (node, code, file, line, nofatal)
- tree node;
+#if defined ENABLE_CHECKING && HAVE_GCC_VERSION(2,7)
+/* Complain that the tree code of NODE does not match the expected CODE.
+ FILE, LINE, and FUNCTION are of the caller. */
+void
+tree_check_failed (node, code, file, line, function)
+ const tree node;
enum tree_code code;
- char *file;
+ const char *file;
int line;
- int nofatal;
+ const char *function;
{
- if (TREE_CODE (node) == code)
- return node;
- else if (nofatal)
- return 0;
- else
- fatal ("%s:%d: Expect %s, have %s\n", file, line,
- tree_code_name[code], tree_code_name[TREE_CODE (node)]);
+ error ("Tree check: expected %s, have %s",
+ tree_code_name[code], tree_code_name[TREE_CODE (node)]);
+ fancy_abort (file, line, function);
}
/* Similar to above, except that we check for a class of tree
code, given in CL. */
-
-tree
-tree_class_check (node, cl, file, line, nofatal)
- tree node;
+void
+tree_class_check_failed (node, cl, file, line, function)
+ const tree node;
char cl;
- char *file;
+ const char *file;
int line;
- int nofatal;
+ const char *function;
{
- if (TREE_CODE_CLASS (TREE_CODE (node)) == cl)
- return node;
- else if (nofatal)
- return 0;
- else
- fatal ("%s:%d: Expect '%c', have '%s'\n", file, line,
- cl, tree_code_name[TREE_CODE (node)]);
+ error ("Tree check: expected class '%c', have '%c' (%s)",
+ cl, TREE_CODE_CLASS (TREE_CODE (node)),
+ tree_code_name[TREE_CODE (node)]);
+ fancy_abort (file, line, function);
}
-/* Likewise, but complain if the tree node is not an expression. */
-
-tree
-expr_check (node, ignored, file, line, nofatal)
- tree node;
- int ignored;
- char *file;
- int line;
- int nofatal;
-{
- switch (TREE_CODE_CLASS (TREE_CODE (node)))
- {
- case 'r':
- case 's':
- case 'e':
- case '<':
- case '1':
- case '2':
- break;
-
- default:
- if (nofatal)
- return 0;
- else
- fatal ("%s:%d: Expect expression, have '%s'\n", file, line,
- tree_code_name[TREE_CODE (node)]);
- }
-
- return node;
-}
-#endif
+#endif /* ENABLE_CHECKING */
/* Return the alias set for T, which may be either a type or an
expression. */
new_alias_set ()
{
static int last_alias_set;
- return ++last_alias_set;
+ if (flag_strict_aliasing)
+ return ++last_alias_set;
+ else
+ return 0;
+}
+\f
+#ifndef CHAR_TYPE_SIZE
+#define CHAR_TYPE_SIZE BITS_PER_UNIT
+#endif
+
+#ifndef SHORT_TYPE_SIZE
+#define SHORT_TYPE_SIZE (BITS_PER_UNIT * MIN ((UNITS_PER_WORD + 1) / 2, 2))
+#endif
+
+#ifndef INT_TYPE_SIZE
+#define INT_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef LONG_TYPE_SIZE
+#define LONG_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef LONG_LONG_TYPE_SIZE
+#define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+#ifndef FLOAT_TYPE_SIZE
+#define FLOAT_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef DOUBLE_TYPE_SIZE
+#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+#ifndef LONG_DOUBLE_TYPE_SIZE
+#define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+/* Create nodes for all integer types (and error_mark_node) using the sizes
+ of C datatypes. The caller should call set_sizetype soon after calling
+ this function to select one of the types as sizetype. */
+
+void
+build_common_tree_nodes (signed_char)
+ int signed_char;
+{
+ error_mark_node = make_node (ERROR_MARK);
+ TREE_TYPE (error_mark_node) = error_mark_node;
+
+ /* Define both `signed char' and `unsigned char'. */
+ signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE);
+ unsigned_char_type_node = make_unsigned_type (CHAR_TYPE_SIZE);
+
+ /* Define `char', which is like either `signed char' or `unsigned char'
+ but not the same as either. */
+ char_type_node
+ = (signed_char
+ ? make_signed_type (CHAR_TYPE_SIZE)
+ : make_unsigned_type (CHAR_TYPE_SIZE));
+
+ short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE);
+ short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE);
+ integer_type_node = make_signed_type (INT_TYPE_SIZE);
+ /* Define an unsigned integer first. make_unsigned_type and make_signed_type
+ both call set_sizetype for the first type that we create, and we want this
+ to be large enough to hold the sizes of various types until we switch to
+ the real sizetype. */
+ unsigned_type_node = make_unsigned_type (INT_TYPE_SIZE);
+ long_integer_type_node = make_signed_type (LONG_TYPE_SIZE);
+ long_unsigned_type_node = make_unsigned_type (LONG_TYPE_SIZE);
+ long_long_integer_type_node = make_signed_type (LONG_LONG_TYPE_SIZE);
+ long_long_unsigned_type_node = make_unsigned_type (LONG_LONG_TYPE_SIZE);
+
+ intQI_type_node = make_signed_type (GET_MODE_BITSIZE (QImode));
+ intHI_type_node = make_signed_type (GET_MODE_BITSIZE (HImode));
+ intSI_type_node = make_signed_type (GET_MODE_BITSIZE (SImode));
+ intDI_type_node = make_signed_type (GET_MODE_BITSIZE (DImode));
+ intTI_type_node = make_signed_type (GET_MODE_BITSIZE (TImode));
+
+ unsigned_intQI_type_node = make_unsigned_type (GET_MODE_BITSIZE (QImode));
+ unsigned_intHI_type_node = make_unsigned_type (GET_MODE_BITSIZE (HImode));
+ unsigned_intSI_type_node = make_unsigned_type (GET_MODE_BITSIZE (SImode));
+ unsigned_intDI_type_node = make_unsigned_type (GET_MODE_BITSIZE (DImode));
+ unsigned_intTI_type_node = make_unsigned_type (GET_MODE_BITSIZE (TImode));
+}
+
+/* For type TYPE, fill in the proper type for TYPE_SIZE and
+ TYPE_SIZE_UNIT. */
+static void
+fix_sizetype (type)
+ tree type;
+{
+ TREE_TYPE (TYPE_SIZE (type)) = bitsizetype;
+ TREE_TYPE (TYPE_SIZE_UNIT (type)) = sizetype;
+}
+
+/* Call this function after calling build_common_tree_nodes and set_sizetype.
+ It will fix the previously made nodes to have proper references to
+ sizetype, and it will create several other common tree nodes. */
+void
+build_common_tree_nodes_2 (short_double)
+ int short_double;
+{
+ fix_sizetype (signed_char_type_node);
+ fix_sizetype (unsigned_char_type_node);
+ fix_sizetype (char_type_node);
+ fix_sizetype (short_integer_type_node);
+ fix_sizetype (short_unsigned_type_node);
+ fix_sizetype (integer_type_node);
+ fix_sizetype (unsigned_type_node);
+ fix_sizetype (long_unsigned_type_node);
+ fix_sizetype (long_integer_type_node);
+ fix_sizetype (long_long_integer_type_node);
+ fix_sizetype (long_long_unsigned_type_node);
+
+ fix_sizetype (intQI_type_node);
+ fix_sizetype (intHI_type_node);
+ fix_sizetype (intSI_type_node);
+ fix_sizetype (intDI_type_node);
+ fix_sizetype (intTI_type_node);
+ fix_sizetype (unsigned_intQI_type_node);
+ fix_sizetype (unsigned_intHI_type_node);
+ fix_sizetype (unsigned_intSI_type_node);
+ fix_sizetype (unsigned_intDI_type_node);
+ fix_sizetype (unsigned_intTI_type_node);
+
+ integer_zero_node = build_int_2 (0, 0);
+ TREE_TYPE (integer_zero_node) = integer_type_node;
+ integer_one_node = build_int_2 (1, 0);
+ TREE_TYPE (integer_one_node) = integer_type_node;
+
+ size_zero_node = build_int_2 (0, 0);
+ TREE_TYPE (size_zero_node) = sizetype;
+ size_one_node = build_int_2 (1, 0);
+ TREE_TYPE (size_one_node) = sizetype;
+
+ void_type_node = make_node (VOID_TYPE);
+ layout_type (void_type_node); /* Uses size_zero_node */
+ /* We are not going to have real types in C with less than byte alignment,
+ so we might as well not have any types that claim to have it. */
+ TYPE_ALIGN (void_type_node) = BITS_PER_UNIT;
+
+ null_pointer_node = build_int_2 (0, 0);
+ TREE_TYPE (null_pointer_node) = build_pointer_type (void_type_node);
+ layout_type (TREE_TYPE (null_pointer_node));
+
+ ptr_type_node = build_pointer_type (void_type_node);
+ const_ptr_type_node
+ = build_pointer_type (build_type_variant (void_type_node, 1, 0));
+
+ float_type_node = make_node (REAL_TYPE);
+ TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE;
+ layout_type (float_type_node);
+
+ double_type_node = make_node (REAL_TYPE);
+ if (short_double)
+ TYPE_PRECISION (double_type_node) = FLOAT_TYPE_SIZE;
+ else
+ TYPE_PRECISION (double_type_node) = DOUBLE_TYPE_SIZE;
+ layout_type (double_type_node);
+
+ long_double_type_node = make_node (REAL_TYPE);
+ TYPE_PRECISION (long_double_type_node) = LONG_DOUBLE_TYPE_SIZE;
+ layout_type (long_double_type_node);
+
+ complex_integer_type_node = make_node (COMPLEX_TYPE);
+ TREE_TYPE (complex_integer_type_node) = integer_type_node;
+ layout_type (complex_integer_type_node);
+
+ complex_float_type_node = make_node (COMPLEX_TYPE);
+ TREE_TYPE (complex_float_type_node) = float_type_node;
+ layout_type (complex_float_type_node);
+
+ complex_double_type_node = make_node (COMPLEX_TYPE);
+ TREE_TYPE (complex_double_type_node) = double_type_node;
+ layout_type (complex_double_type_node);
+
+ complex_long_double_type_node = make_node (COMPLEX_TYPE);
+ TREE_TYPE (complex_long_double_type_node) = long_double_type_node;
+ layout_type (complex_long_double_type_node);
+
+#ifdef BUILD_VA_LIST_TYPE
+ BUILD_VA_LIST_TYPE(va_list_type_node);
+#else
+ va_list_type_node = ptr_type_node;
+#endif
}