/* Language-independent node constructors for parse phase of GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of GCC.
nodes of that code.
It is intended to be language-independent, but occasionally
- calls language-dependent routines defined (for C) in typecheck.c.
-
- The low-level allocation routines oballoc and permalloc
- are used also for allocating many other kinds of objects
- by all passes of the compiler. */
+ calls language-dependent routines defined (for C) in typecheck.c. */
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "flags.h"
#include "tree.h"
#include "real.h"
/* obstack.[ch] explicitly declined to prototype this. */
extern int _obstack_allocated_p PARAMS ((struct obstack *h, PTR obj));
-/* Objects allocated on this obstack last forever. */
-
-struct obstack permanent_obstack;
-
#ifdef GATHER_STATISTICS
/* Statistics-gathering stuff. */
typedef enum
#endif /* GATHER_STATISTICS */
/* Unique id for next decl created. */
-static int next_decl_uid;
+static GTY(()) int next_decl_uid;
/* Unique id for next type created. */
-static int next_type_uid = 1;
+static GTY(()) int next_type_uid = 1;
/* Since we cannot rehash a type after it is in the table, we have to
keep the hash code. */
static void set_type_quals PARAMS ((tree, int));
static void append_random_chars PARAMS ((char *));
static int type_hash_eq PARAMS ((const void *, const void *));
-static unsigned int type_hash_hash PARAMS ((const void *));
+static hashval_t type_hash_hash PARAMS ((const void *));
static void print_type_hash_statistics PARAMS((void));
static void finish_vector_type PARAMS((tree));
static tree make_vector PARAMS ((enum machine_mode, tree, int));
tree global_trees[TI_MAX];
tree integer_types[itk_none];
\f
-/* Init the principal obstacks. */
+/* Init tree.c. */
void
-init_obstacks ()
+init_ttree ()
{
- gcc_obstack_init (&permanent_obstack);
-
/* Initialize the hash table of types. */
- type_hash_table = htab_create (TYPE_HASH_INITIAL_SIZE, type_hash_hash,
- type_hash_eq, 0);
+ type_hash_table = htab_create_ggc (TYPE_HASH_INITIAL_SIZE, type_hash_hash,
+ type_hash_eq, 0);
}
\f
-/* Allocate SIZE bytes in the permanent obstack
- and return a pointer to them. */
-
-char *
-permalloc (size)
- int size;
-{
- return (char *) obstack_alloc (&permanent_obstack, size);
-}
-
-/* Allocate NELEM items of SIZE bytes in the permanent obstack
- and return a pointer to them. The storage is cleared before
- returning the value. */
-
-char *
-perm_calloc (nelem, size)
- int nelem;
- long size;
-{
- char *rval = (char *) obstack_alloc (&permanent_obstack, nelem * size);
- memset (rval, 0, nelem * size);
- return rval;
-}
-
/* The name of the object as the assembler will see it (but before any
translations made by ASM_OUTPUT_LABELREF). Often this is the same
as DECL_NAME. It is an IDENTIFIER_NODE. */
case '1': /* a unary arithmetic expression */
case '2': /* a binary arithmetic expression */
return (sizeof (struct tree_exp)
- + (TREE_CODE_LENGTH (code) - 1) * sizeof (char *));
+ + TREE_CODE_LENGTH (code) * sizeof (char *) - sizeof (char *));
case 'c': /* a constant */
- /* We can't use TREE_CODE_LENGTH for INTEGER_CST, since the number of
- words is machine-dependent due to varying length of HOST_WIDE_INT,
- which might be wider than a pointer (e.g., long long). Similarly
- for REAL_CST, since the number of words is machine-dependent due
- to varying size and alignment of `double'. */
- if (code == INTEGER_CST)
- return sizeof (struct tree_int_cst);
- else if (code == REAL_CST)
- return sizeof (struct tree_real_cst);
- else
- return (sizeof (struct tree_common)
- + TREE_CODE_LENGTH (code) * sizeof (char *));
+ switch (code)
+ {
+ case INTEGER_CST: return sizeof (struct tree_int_cst);
+ case REAL_CST: return sizeof (struct tree_real_cst);
+ case COMPLEX_CST: return sizeof (struct tree_complex);
+ case VECTOR_CST: return sizeof (struct tree_vector);
+ case STRING_CST: return sizeof (struct tree_string);
+ default:
+ return (*lang_hooks.tree_size) (code);
+ }
case 'x': /* something random, like an identifier. */
- {
- size_t length;
- length = (sizeof (struct tree_common)
- + TREE_CODE_LENGTH (code) * sizeof (char *));
- if (code == TREE_VEC)
- length += (TREE_VEC_LENGTH (node) - 1) * sizeof (char *);
- return length;
- }
+ switch (code)
+ {
+ case IDENTIFIER_NODE: return lang_hooks.identifier_size;
+ case TREE_LIST: return sizeof (struct tree_list);
+ case TREE_VEC: return (sizeof (struct tree_vec)
+ + TREE_VEC_LENGTH(node) * sizeof(char *)
+ - sizeof (char *));
+
+ case ERROR_MARK:
+ case PLACEHOLDER_EXPR: return sizeof (struct tree_common);
+
+ default:
+ return (*lang_hooks.tree_size) (code);
+ }
default:
abort ();
{
case 's':
TREE_SIDE_EFFECTS (t) = 1;
- TREE_TYPE (t) = void_type_node;
break;
case 'd':
DECL_ALIGN (t) = 1;
DECL_USER_ALIGN (t) = 0;
DECL_IN_SYSTEM_HEADER (t) = in_system_header;
- DECL_SOURCE_LINE (t) = lineno;
+ DECL_SOURCE_LINE (t) = input_line;
DECL_SOURCE_FILE (t) =
(input_filename) ? input_filename : "<built-in>";
DECL_UID (t) = next_decl_uid++;
return v;
}
+/* Return a new CONSTRUCTOR node whose type is TYPE and whose values
+ are in a list pointed to by VALS. */
+tree
+build_constructor (type, vals)
+ tree type, vals;
+{
+ tree c = make_node (CONSTRUCTOR);
+ TREE_TYPE (c) = type;
+ CONSTRUCTOR_ELTS (c) = vals;
+
+ /* ??? May not be necessary. Mirrors what build does. */
+ if (vals)
+ {
+ TREE_SIDE_EFFECTS (c) = TREE_SIDE_EFFECTS (vals);
+ TREE_READONLY (c) = TREE_READONLY (vals);
+ TREE_CONSTANT (c) = TREE_CONSTANT (vals);
+ }
+ else
+ TREE_CONSTANT (c) = 0; /* safe side */
+
+ return c;
+}
+
/* Return a new REAL_CST node whose type is TYPE and value is D. */
tree
REAL_VALUE_TYPE *dp;
int overflow = 0;
- /* Check for valid float value for this type on this target machine;
- if not, can print error message and store a valid value in D. */
-#ifdef CHECK_FLOAT_VALUE
- CHECK_FLOAT_VALUE (TYPE_MODE (type), d, overflow);
-#endif
+ /* ??? Used to check for overflow here via CHECK_FLOAT_TYPE.
+ Consider doing it via real_convert now. */
v = make_node (REAL_CST);
dp = ggc_alloc (sizeof (REAL_VALUE_TYPE));
|| (low == 0 && (high & (high - 1)) == 0));
}
+/* Return 1 if EXPR is an integer constant other than zero or a
+ complex constant other than zero. */
+
+int
+integer_nonzerop (expr)
+ tree expr;
+{
+ STRIP_NOPS (expr);
+
+ return ((TREE_CODE (expr) == INTEGER_CST
+ && ! TREE_CONSTANT_OVERFLOW (expr)
+ && (TREE_INT_CST_LOW (expr) != 0
+ || TREE_INT_CST_HIGH (expr) != 0))
+ || (TREE_CODE (expr) == COMPLEX_CST
+ && (integer_nonzerop (TREE_REALPART (expr))
+ || integer_nonzerop (TREE_IMAGPART (expr)))));
+}
+
/* Return the power of two represented by a tree node known to be a
power of two. */
return 0;
}
-/* Return nonzero if ELEM is equal to TREE_VALUE (CHAIN) for any piece of
- chain CHAIN. This and the next function are currently unused, but
- are retained for completeness. */
-
-int
-chain_member_value (elem, chain)
- tree elem, chain;
-{
- while (chain)
- {
- if (elem == TREE_VALUE (chain))
- return 1;
- chain = TREE_CHAIN (chain);
- }
-
- return 0;
-}
-
-/* Return nonzero if ELEM is equal to TREE_PURPOSE (CHAIN)
- for any piece of chain CHAIN. */
-
-int
-chain_member_purpose (elem, chain)
- tree elem, chain;
-{
- while (chain)
- {
- if (elem == TREE_PURPOSE (chain))
- return 1;
- chain = TREE_CHAIN (chain);
- }
-
- return 0;
-}
-
/* Return the length of a chain of nodes chained through TREE_CHAIN.
We expect a null pointer to mark the end of the chain.
This is the Lisp primitive `length'. */
chainon (op1, op2)
tree op1, op2;
{
+ tree t1;
- if (op1)
- {
- tree t1;
-#ifdef ENABLE_TREE_CHECKING
- tree t2;
-#endif
+ if (!op1)
+ return op2;
+ if (!op2)
+ return op1;
+
+ for (t1 = op1; TREE_CHAIN (t1); t1 = TREE_CHAIN (t1))
+ continue;
+ TREE_CHAIN (t1) = op2;
- for (t1 = op1; TREE_CHAIN (t1); t1 = TREE_CHAIN (t1))
- ;
- TREE_CHAIN (t1) = op2;
#ifdef ENABLE_TREE_CHECKING
- for (t2 = op2; t2; t2 = TREE_CHAIN (t2))
- if (t2 == t1)
- abort (); /* Circularity created. */
+ {
+ tree t2;
+ for (t2 = op2; t2; t2 = TREE_CHAIN (t2))
+ if (t2 == t1)
+ abort (); /* Circularity created. */
+ }
#endif
- return op1;
- }
- else
- return op2;
+
+ return op1;
}
/* Return the last node in a chain of nodes (chained through TREE_CHAIN). */
}
return prev;
}
-
-/* Given a chain CHAIN of tree nodes,
- construct and return a list of those nodes. */
-
-tree
-listify (chain)
- tree chain;
-{
- tree result = NULL_TREE;
- tree in_tail = chain;
- tree out_tail = NULL_TREE;
-
- while (in_tail)
- {
- tree next = tree_cons (NULL_TREE, in_tail, NULL_TREE);
- if (out_tail)
- TREE_CHAIN (out_tail) = next;
- else
- result = next;
- out_tail = next;
- in_tail = TREE_CHAIN (in_tail);
- }
-
- return result;
-}
\f
/* Return a newly created TREE_LIST node whose
purpose and value fields are PARM and VALUE. */
}
/* Return a newly created TREE_LIST node whose
- purpose and value fields are PARM and VALUE
+ purpose and value fields are PURPOSE and VALUE
and whose TREE_CHAIN is CHAIN. */
tree
return node;
}
+/* Return the last expression in a sequence of COMPOUND_EXPRs. */
+
+tree
+expr_last (expr)
+ tree expr;
+{
+ if (expr == NULL_TREE)
+ return expr;
+ while (TREE_CODE (expr) == COMPOUND_EXPR)
+ expr = TREE_OPERAND (expr, 1);
+ return expr;
+}
\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,
bit_position (field)
tree field;
{
-
return bit_from_pos (DECL_FIELD_OFFSET (field),
DECL_FIELD_BIT_OFFSET (field));
}
save_expr (expr)
tree expr;
{
- tree t = fold (expr);
+ tree t = expr;
tree inner;
- /* We don't care about whether this can be used as an lvalue in this
- context. */
- while (TREE_CODE (t) == NON_LVALUE_EXPR)
- t = TREE_OPERAND (t, 0);
-
- /* If we have simple operations applied to a SAVE_EXPR or to a SAVE_EXPR and
- a constant, it will be more efficient to not make another SAVE_EXPR since
- it will allow better simplification and GCSE will be able to merge the
- computations if they actualy occur. */
- for (inner = t;
- (TREE_CODE_CLASS (TREE_CODE (inner)) == '1'
- || (TREE_CODE_CLASS (TREE_CODE (inner)) == '2'
- && TREE_CONSTANT (TREE_OPERAND (inner, 1))));
- inner = TREE_OPERAND (inner, 0))
- ;
+ /* Don't fold a COMPONENT_EXPR: if the operand was a CONSTRUCTOR (the
+ only time it will fold), it can cause problems with PLACEHOLDER_EXPRs
+ in Ada. Moreover, it isn't at all clear why we fold here at all. */
+ if (TREE_CODE (t) != COMPONENT_REF)
+ t = fold (t);
/* If the tree evaluates to a constant, then we don't want to hide that
fact (i.e. this allows further folding, and direct checks for constants).
However, a read-only object that has side effects cannot be bypassed.
Since it is no problem to reevaluate literals, we just return the
literal node. */
+ inner = skip_simple_arithmetic (t);
if (TREE_CONSTANT (inner)
|| (TREE_READONLY (inner) && ! TREE_SIDE_EFFECTS (inner))
- || TREE_CODE (inner) == SAVE_EXPR || TREE_CODE (inner) == ERROR_MARK)
+ || TREE_CODE (inner) == SAVE_EXPR
+ || TREE_CODE (inner) == ERROR_MARK)
return t;
- /* If T contains a PLACEHOLDER_EXPR, we must evaluate it each time, since
+ /* If INNER contains a PLACEHOLDER_EXPR, we must evaluate it each time, since
it means that the size or offset of some field of an object depends on
the value within another field.
evaluated more than once. Front-ends must assure this case cannot
happen by surrounding any such subexpressions in their own SAVE_EXPR
and forcing evaluation at the proper time. */
- if (contains_placeholder_p (t))
+ if (contains_placeholder_p (inner))
return t;
t = build (SAVE_EXPR, TREE_TYPE (expr), t, current_function_decl, NULL_TREE);
return t;
}
+/* Look inside EXPR and into any simple arithmetic operations. Return
+ the innermost non-arithmetic node. */
+
+tree
+skip_simple_arithmetic (expr)
+ tree expr;
+{
+ tree inner;
+
+ /* We don't care about whether this can be used as an lvalue in this
+ context. */
+ while (TREE_CODE (expr) == NON_LVALUE_EXPR)
+ expr = TREE_OPERAND (expr, 0);
+
+ /* If we have simple operations applied to a SAVE_EXPR or to a SAVE_EXPR and
+ a constant, it will be more efficient to not make another SAVE_EXPR since
+ it will allow better simplification and GCSE will be able to merge the
+ computations if they actually occur. */
+ inner = expr;
+ while (1)
+ {
+ if (TREE_CODE_CLASS (TREE_CODE (inner)) == '1')
+ inner = TREE_OPERAND (inner, 0);
+ else if (TREE_CODE_CLASS (TREE_CODE (inner)) == '2')
+ {
+ if (TREE_CONSTANT (TREE_OPERAND (inner, 1)))
+ inner = TREE_OPERAND (inner, 0);
+ else if (TREE_CONSTANT (TREE_OPERAND (inner, 0)))
+ inner = TREE_OPERAND (inner, 1);
+ else
+ break;
+ }
+ else
+ break;
+ }
+
+ return inner;
+}
+
+/* Return TRUE if EXPR is a SAVE_EXPR or wraps simple arithmetic around a
+ SAVE_EXPR. Return FALSE otherwise. */
+
+bool
+saved_expr_p (expr)
+ tree expr;
+{
+ return TREE_CODE (skip_simple_arithmetic (expr)) == SAVE_EXPR;
+}
+
/* Arrange for an expression to be expanded multiple independent
times. This is useful for cleanup actions, as the backend can
expand them multiple times in different places. */
{
int unsafeness = 0;
enum tree_code code;
- int i, tmp;
+ int i, tmp, tmp2;
tree exp;
int first_rtl;
return unsafeness;
case CALL_EXPR:
+ tmp2 = unsafe_for_reeval (TREE_OPERAND (expr, 0));
tmp = unsafe_for_reeval (TREE_OPERAND (expr, 1));
- return MAX (tmp, 1);
+ return MAX (MAX (tmp, 1), tmp2);
case TARGET_EXPR:
unsafeness = 1;
else if (code == CONSTRUCTOR)
abort ();
- op0 = substitute_in_expr (TREE_OPERAND (exp, 0), f, r);
- op1 = substitute_in_expr (TREE_OPERAND (exp, 1), f, r);
+ op0 = TREE_OPERAND (exp, 0);
+ op1 = TREE_OPERAND (exp, 1);
+ if (contains_placeholder_p (op0))
+ op0 = substitute_in_expr (op0, f, r);
+ if (contains_placeholder_p (op1))
+ op1 = substitute_in_expr (op1, f, r);
+
if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1))
return exp;
else if (code != COND_EXPR)
abort ();
- op0 = substitute_in_expr (TREE_OPERAND (exp, 0), f, r);
- op1 = substitute_in_expr (TREE_OPERAND (exp, 1), f, r);
- op2 = substitute_in_expr (TREE_OPERAND (exp, 2), f, r);
+ op0 = TREE_OPERAND (exp, 0);
+ op1 = TREE_OPERAND (exp, 1);
+ op2 = TREE_OPERAND (exp, 2);
+
+ if (contains_placeholder_p (op0))
+ op0 = substitute_in_expr (op0, f, r);
+ if (contains_placeholder_p (op1))
+ op1 = substitute_in_expr (op1, f, r);
+ if (contains_placeholder_p (op2))
+ op2 = substitute_in_expr (op2, f, r);
+
if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1)
&& op2 == TREE_OPERAND (exp, 2))
return exp;
Constants, decls, types and misc nodes cannot be. */
tree
-build VPARAMS ((enum tree_code code, tree tt, ...))
+build (enum tree_code code, tree tt, ...)
{
tree t;
int length;
int i;
int fro;
int constant;
+ va_list p;
- VA_OPEN (p, tt);
- VA_FIXEDARG (p, enum tree_code, code);
- VA_FIXEDARG (p, tree, tt);
+ va_start (p, tt);
t = make_node (code);
length = TREE_CODE_LENGTH (code);
}
}
}
- VA_CLOSE (p);
+ va_end (p);
TREE_CONSTANT (t) = constant;
return t;
tree type;
tree node;
{
- int length;
+ int length = sizeof (struct tree_exp);
#ifdef GATHER_STATISTICS
tree_node_kind kind;
#endif
tree t;
#ifdef GATHER_STATISTICS
- if (TREE_CODE_CLASS (code) == 'r')
- kind = r_kind;
- else
- kind = e_kind;
+ switch (TREE_CODE_CLASS (code))
+ {
+ case 's': /* an expression with side effects */
+ kind = s_kind;
+ break;
+ case 'r': /* a reference */
+ kind = r_kind;
+ break;
+ default:
+ kind = e_kind;
+ break;
+ }
+
+ tree_node_counts[(int) kind]++;
+ tree_node_sizes[(int) kind] += length;
#endif
#ifdef ENABLE_CHECKING
abort ();
#endif /* ENABLE_CHECKING */
- length = sizeof (struct tree_exp);
-
t = ggc_alloc_tree (length);
memset ((PTR) t, 0, sizeof (struct tree_common));
-#ifdef GATHER_STATISTICS
- tree_node_counts[(int) kind]++;
- tree_node_sizes[(int) kind] += length;
-#endif
-
TREE_SET_CODE (t, code);
TREE_TYPE (t) = type;
TREE_READONLY (t) = TREE_READONLY (node);
}
- switch (code)
+ if (TREE_CODE_CLASS (code) == 's')
+ TREE_SIDE_EFFECTS (t) = 1;
+ else switch (code)
{
case INIT_EXPR:
case MODIFY_EXPR:
or even garbage if their values do not matter. */
tree
-build_nt VPARAMS ((enum tree_code code, ...))
+build_nt (enum tree_code code, ...)
{
tree t;
int length;
int i;
+ va_list p;
- VA_OPEN (p, code);
- VA_FIXEDARG (p, enum tree_code, code);
+ va_start (p, code);
t = make_node (code);
length = TREE_CODE_LENGTH (code);
for (i = 0; i < length; i++)
TREE_OPERAND (t, i) = va_arg (p, tree);
- VA_CLOSE (p);
+ va_end (p);
return t;
}
\f
return ttype;
}
-/* Default value of targetm.comp_type_attributes that always returns 1. */
-
-int
-default_comp_type_attributes (type1, type2)
- tree type1 ATTRIBUTE_UNUSED;
- tree type2 ATTRIBUTE_UNUSED;
-{
- return 1;
-}
-
-/* Default version of targetm.set_default_type_attributes that always does
- nothing. */
-
-void
-default_set_default_type_attributes (type)
- tree type ATTRIBUTE_UNUSED;
-{
-}
-
-/* Default version of targetm.insert_attributes that always does nothing. */
-void
-default_insert_attributes (decl, attr_ptr)
- tree decl ATTRIBUTE_UNUSED;
- tree *attr_ptr ATTRIBUTE_UNUSED;
-{
-}
-
-/* Default value of targetm.function_attribute_inlinable_p that always
- returns false. */
-bool
-default_function_attribute_inlinable_p (fndecl)
- tree fndecl ATTRIBUTE_UNUSED;
-{
- /* By default, functions with machine attributes cannot be inlined. */
- return false;
-}
-
-/* Default value of targetm.ms_bitfield_layout_p that always returns
- false. */
-bool
-default_ms_bitfield_layout_p (record)
- tree record ATTRIBUTE_UNUSED;
-{
- /* By default, GCC does not use the MS VC++ bitfield layout rules. */
- return false;
-}
-
-/* Return non-zero if IDENT is a valid name for attribute ATTR,
+/* Return nonzero if IDENT is a valid name for attribute ATTR,
or zero if not.
We try both `text' and `__text__', ATTR may be either one. */
like the one we need to have. If so, use that existing one. We must
preserve the TYPE_NAME, since there is code that depends on this. */
for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
- if (TYPE_QUALS (t) == type_quals && TYPE_NAME (t) == TYPE_NAME (type))
+ if (TYPE_QUALS (t) == type_quals && TYPE_NAME (t) == TYPE_NAME (type)
+ && TYPE_CONTEXT (t) == TYPE_CONTEXT (type))
return t;
return NULL_TREE;
/* Return the cached hash value. */
-static unsigned int
+static hashval_t
type_hash_hash (item)
const void *item;
{
else
return 1;
}
+
+/* Generate a hash value for an expression. This can be used iteratively
+ by passing a previous result as the "val" argument.
+
+ This function is intended to produce the same hash for expressions which
+ would compare equal using operand_equal_p. */
+
+hashval_t
+iterative_hash_expr (tree t, hashval_t val)
+{
+ int i;
+ enum tree_code code;
+ char class;
+
+ if (t == NULL_TREE)
+ return iterative_hash_object (t, val);
+
+ code = TREE_CODE (t);
+ class = TREE_CODE_CLASS (code);
+
+ if (class == 'd')
+ {
+ /* Decls we can just compare by pointer. */
+ val = iterative_hash_object (t, val);
+ }
+ else if (class == 'c')
+ {
+ /* Alas, constants aren't shared, so we can't rely on pointer
+ identity. */
+ if (code == INTEGER_CST)
+ {
+ val = iterative_hash_object (TREE_INT_CST_LOW (t), val);
+ val = iterative_hash_object (TREE_INT_CST_HIGH (t), val);
+ }
+ else if (code == REAL_CST)
+ val = iterative_hash (TREE_REAL_CST_PTR (t),
+ sizeof (REAL_VALUE_TYPE), val);
+ else if (code == STRING_CST)
+ val = iterative_hash (TREE_STRING_POINTER (t),
+ TREE_STRING_LENGTH (t), val);
+ else if (code == COMPLEX_CST)
+ {
+ val = iterative_hash_expr (TREE_REALPART (t), val);
+ val = iterative_hash_expr (TREE_IMAGPART (t), val);
+ }
+ else if (code == VECTOR_CST)
+ val = iterative_hash_expr (TREE_VECTOR_CST_ELTS (t), val);
+ else
+ abort ();
+ }
+ else if (IS_EXPR_CODE_CLASS (class) || class == 'r')
+ {
+ val = iterative_hash_object (code, val);
+
+ if (code == NOP_EXPR || code == CONVERT_EXPR
+ || code == NON_LVALUE_EXPR)
+ val = iterative_hash_object (TREE_TYPE (t), val);
+
+ for (i = first_rtl_op (code) - 1; i >= 0; --i)
+ val = iterative_hash_expr (TREE_OPERAND (t, i), val);
+ }
+ else if (code == TREE_LIST)
+ {
+ /* A list of expressions, for a CALL_EXPR or as the elements of a
+ VECTOR_CST. */
+ for (; t; t = TREE_CHAIN (t))
+ val = iterative_hash_expr (TREE_VALUE (t), val);
+ }
+ else
+ abort ();
+
+ return val;
+}
\f
/* Constructors for pointer, array and function types.
(RECORD_TYPE, UNION_TYPE and ENUMERAL_TYPE nodes are
constructed by language-dependent code, not here.) */
-/* Construct, lay out and return the type of pointers to TO_TYPE.
- If such a type has already been constructed, reuse it. */
+/* Construct, lay out and return the type of pointers to TO_TYPE
+ with mode MODE. If such a type has already been constructed,
+ reuse it. */
tree
-build_pointer_type (to_type)
+build_pointer_type_for_mode (to_type, mode)
tree to_type;
+ enum machine_mode mode;
{
tree t = TYPE_POINTER_TO (to_type);
/* First, if we already have a type for pointers to TO_TYPE, use it. */
-
- if (t != 0)
+ if (t != 0 && mode == ptr_mode)
return t;
- /* We need a new one. */
t = make_node (POINTER_TYPE);
TREE_TYPE (t) = to_type;
+ TYPE_MODE (t) = mode;
/* Record this type as the pointer to TO_TYPE. */
+ if (mode == ptr_mode)
TYPE_POINTER_TO (to_type) = t;
/* Lay out the type. This function has many callers that are concerned
return t;
}
-/* Build the node for the type of references-to-TO_TYPE. */
+/* By default build pointers in ptr_mode. */
tree
-build_reference_type (to_type)
+build_pointer_type (to_type)
tree to_type;
{
+ return build_pointer_type_for_mode (to_type, ptr_mode);
+}
+
+/* Construct, lay out and return the type of references to TO_TYPE
+ with mode MODE. If such a type has already been constructed,
+ reuse it. */
+
+tree
+build_reference_type_for_mode (to_type, mode)
+ tree to_type;
+ enum machine_mode mode;
+{
tree t = TYPE_REFERENCE_TO (to_type);
/* First, if we already have a type for pointers to TO_TYPE, use it. */
-
- if (t)
+ if (t != 0 && mode == ptr_mode)
return t;
- /* We need a new one. */
t = make_node (REFERENCE_TYPE);
TREE_TYPE (t) = to_type;
+ TYPE_MODE (t) = mode;
/* Record this type as the pointer to TO_TYPE. */
+ if (mode == ptr_mode)
TYPE_REFERENCE_TO (to_type) = t;
layout_type (t);
return t;
}
+
+/* Build the node for the type of references-to-TO_TYPE by default
+ in ptr_mode. */
+
+tree
+build_reference_type (to_type)
+ tree to_type;
+{
+ return build_reference_type_for_mode (to_type, ptr_mode);
+}
+
/* Build a type that is compatible with t but has no cv quals anywhere
in its type, thus
return build_range_type (sizetype, lowval, highval);
}
-/* Return nonzero iff ITYPE1 and ITYPE2 are equal (in the LISP sense).
- Needed because when index types are not hashed, equal index types
- built at different times appear distinct, even though structurally,
- they are not. */
-
-int
-index_type_equal (itype1, itype2)
- tree itype1, itype2;
-{
- if (TREE_CODE (itype1) != TREE_CODE (itype2))
- return 0;
-
- if (TREE_CODE (itype1) == INTEGER_TYPE)
- {
- if (TYPE_PRECISION (itype1) != TYPE_PRECISION (itype2)
- || TYPE_MODE (itype1) != TYPE_MODE (itype2)
- || simple_cst_equal (TYPE_SIZE (itype1), TYPE_SIZE (itype2)) != 1
- || TYPE_ALIGN (itype1) != TYPE_ALIGN (itype2))
- return 0;
-
- if (1 == simple_cst_equal (TYPE_MIN_VALUE (itype1),
- TYPE_MIN_VALUE (itype2))
- && 1 == simple_cst_equal (TYPE_MAX_VALUE (itype1),
- TYPE_MAX_VALUE (itype2)))
- return 1;
- }
-
- return 0;
-}
-
/* Construct, lay out and return the type of arrays of elements with ELT_TYPE
and number of elements specified by the range of values of INDEX_TYPE.
If such a type has already been constructed, reuse it. */
be terminated by NULL_TREE. */
tree
-build_function_type_list VPARAMS ((tree return_type, ...))
+build_function_type_list (tree return_type, ...)
{
tree t, args, last;
+ va_list p;
- VA_OPEN (p, return_type);
- VA_FIXEDARG (p, tree, return_type);
+ va_start (p, return_type);
t = va_arg (p, tree);
for (args = NULL_TREE; t != NULL_TREE; t = va_arg (p, tree))
TREE_CHAIN (last) = void_list_node;
args = build_function_type (return_type, args);
- VA_CLOSE (p);
+ va_end (p);
return args;
}
/* See what's inside this conversion. If we decide to strip it,
we will set WIN. */
- op = TREE_OPERAND (op, 0);
if (bitschange > 0)
{
+ op = TREE_OPERAND (op, 0);
/* An extension: the outermost one can be stripped,
but remember whether it is zero or sign extension. */
if (first)
if (first)
uns = TREE_UNSIGNED (TREE_TYPE (op));
first = 0;
+ op = TREE_OPERAND (op, 0);
}
win = op;
int_fits_type_p (c, type)
tree c, type;
{
- /* If the bounds of the type are integers, we can check ourselves.
- If not, but this type is a subtype, try checking against that.
- 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)
+ tree type_low_bound = TYPE_MIN_VALUE (type);
+ tree type_high_bound = TYPE_MAX_VALUE (type);
+ int ok_for_low_bound, ok_for_high_bound;
+
+ /* Perform some generic filtering first, which may allow making a decision
+ even if the bounds are not constant. First, negative integers never fit
+ in unsigned types, */
+ if ((TREE_UNSIGNED (type) && tree_int_cst_sgn (c) < 0)
+ /* Also, unsigned integers with top bit set never fit signed types. */
+ || (! TREE_UNSIGNED (type)
+ && TREE_UNSIGNED (TREE_TYPE (c)) && tree_int_cst_msb (c)))
+ return 0;
+
+ /* If at least one bound of the type is a constant integer, we can check
+ ourselves and maybe make a decision. If no such decision is possible, but
+ this type is a subtype, try checking against that. Otherwise, use
+ force_fit_type, which checks against the precision.
+
+ Compute the status for each possibly constant bound, and return if we see
+ one does not match. Use ok_for_xxx_bound for this purpose, assigning -1
+ for "unknown if constant fits", 0 for "constant known *not* to fit" and 1
+ for "constant known to fit". */
+
+ ok_for_low_bound = -1;
+ ok_for_high_bound = -1;
+
+ /* Check if C >= type_low_bound. */
+ if (type_low_bound && TREE_CODE (type_low_bound) == 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))));
+ ok_for_low_bound = ! tree_int_cst_lt (c, type_low_bound);
+ if (! ok_for_low_bound)
+ return 0;
}
+
+ /* Check if c <= type_high_bound. */
+ if (type_high_bound && TREE_CODE (type_high_bound) == INTEGER_CST)
+ {
+ ok_for_high_bound = ! tree_int_cst_lt (type_high_bound, c);
+ if (! ok_for_high_bound)
+ return 0;
+ }
+
+ /* If the constant fits both bounds, the result is known. */
+ if (ok_for_low_bound == 1 && ok_for_high_bound == 1)
+ return 1;
+
+ /* If we haven't been able to decide at this point, there nothing more we
+ can check ourselves here. Look at the base type if we have one. */
else if (TREE_CODE (type) == INTEGER_TYPE && TREE_TYPE (type) != 0)
return int_fits_type_p (c, TREE_TYPE (type));
+
+ /* Or to force_fit_type, if nothing else. */
else
{
c = copy_node (c);
}
}
+/* Returns true if T is, contains, or refers to a type with variable
+ size. This concept is more general than that of C99 'variably
+ modified types': in C99, a struct type is never variably modified
+ because a VLA may not appear as a structure member. However, in
+ GNU C code like:
+
+ struct S { int i[f()]; };
+
+ is valid, and other languages may define similar constructs. */
+
+bool
+variably_modified_type_p (type)
+ tree type;
+{
+ if (type == error_mark_node)
+ return false;
+
+ /* If TYPE itself has variable size, it is variably modified.
+
+ We do not yet have a representation of the C99 '[*]' syntax.
+ When a representation is chosen, this function should be modified
+ to test for that case as well. */
+ if (TYPE_SIZE (type)
+ && TYPE_SIZE (type) != error_mark_node
+ && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+ return true;
+
+ /* If TYPE is a pointer or reference, it is variably modified if
+ the type pointed to is variably modified. */
+ if ((TREE_CODE (type) == POINTER_TYPE
+ || TREE_CODE (type) == REFERENCE_TYPE)
+ && variably_modified_type_p (TREE_TYPE (type)))
+ return true;
+
+ /* If TYPE is an array, it is variably modified if the array
+ elements are. (Note that the VLA case has already been checked
+ above.) */
+ if (TREE_CODE (type) == ARRAY_TYPE
+ && variably_modified_type_p (TREE_TYPE (type)))
+ return true;
+
+ /* If TYPE is a function type, it is variably modified if any of the
+ parameters or the return type are variably modified. */
+ if (TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == METHOD_TYPE)
+ {
+ tree parm;
+
+ if (variably_modified_type_p (TREE_TYPE (type)))
+ return true;
+ for (parm = TYPE_ARG_TYPES (type);
+ parm && parm != void_list_node;
+ parm = TREE_CHAIN (parm))
+ if (variably_modified_type_p (TREE_VALUE (parm)))
+ return true;
+ }
+
+ /* The current language may have other cases to check, but in general,
+ all other types are not variably modified. */
+ return (*lang_hooks.tree_inlining.var_mod_type_p) (type);
+}
+
/* Given a DECL or TYPE, return the scope in which it was declared, or
NULL_TREE if there is no containing scope. */
return NULL_TREE;
}
-/* Print debugging information about the obstack O, named STR. */
-
-void
-print_obstack_statistics (str, o)
- const char *str;
- struct obstack *o;
-{
- struct _obstack_chunk *chunk = o->chunk;
- int n_chunks = 1;
- int n_alloc = 0;
-
- n_alloc += o->next_free - chunk->contents;
- chunk = chunk->prev;
- while (chunk)
- {
- n_chunks += 1;
- n_alloc += chunk->limit - &chunk->contents[0];
- chunk = chunk->prev;
- }
- fprintf (stderr, "obstack %s: %u bytes, %d chunks\n",
- str, n_alloc, n_chunks);
-}
-
/* Print debugging information about tree nodes generated during the compile,
and any language-specific information. */
#else
fprintf (stderr, "(No per-node statistics)\n");
#endif
- print_obstack_statistics ("permanent_obstack", &permanent_obstack);
print_type_hash_statistics ();
(*lang_hooks.print_statistics) ();
}
\f
#define FILE_FUNCTION_FORMAT "_GLOBAL__%s_%s"
+const char *flag_random_seed;
+
+/* Set up a default flag_random_seed value, if there wasn't one already. */
+
+void
+default_flag_random_seed (void)
+{
+ unsigned HOST_WIDE_INT value;
+ char *new_random_seed;
+
+ if (flag_random_seed != NULL)
+ return;
+
+ /* Get some more or less random data. */
+#ifdef HAVE_GETTIMEOFDAY
+ {
+ struct timeval tv;
+
+ gettimeofday (&tv, NULL);
+ value = (((unsigned HOST_WIDE_INT) tv.tv_usec << 16)
+ ^ tv.tv_sec ^ getpid ());
+ }
+#else
+ value = getpid ();
+#endif
+
+ /* This slightly overestimates the space required. */
+ new_random_seed = xmalloc (HOST_BITS_PER_WIDE_INT / 3 + 2);
+ sprintf (new_random_seed, HOST_WIDE_INT_PRINT_UNSIGNED, value);
+ flag_random_seed = new_random_seed;
+}
+
/* Appends 6 random characters to TEMPLATE to (hopefully) avoid name
clashes in cases where we can't reliably choose a unique name.
{
static const char letters[]
= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- static unsigned HOST_WIDE_INT value;
unsigned HOST_WIDE_INT v;
+ size_t i;
- if (! value)
- {
- struct stat st;
-
- /* VALUE should be unique for each file and must not change between
- compiles since this can cause bootstrap comparison errors. */
+ default_flag_random_seed ();
- if (stat (main_input_filename, &st) < 0)
- {
- /* This can happen when preprocessed text is shipped between
- machines, e.g. with bug reports. Assume that uniqueness
- isn't actually an issue. */
- value = 1;
- }
- else
- {
- /* In VMS, ino is an array, so we have to use both values. We
- conditionalize that. */
-#ifdef VMS
-#define INO_TO_INT(INO) ((int) (INO)[1] << 16 ^ (int) (INO)[2])
-#else
-#define INO_TO_INT(INO) INO
-#endif
- value = st.st_dev ^ INO_TO_INT (st.st_ino) ^ st.st_mtime;
- }
- }
+ /* This isn't a very good hash, but it does guarantee no collisions
+ when the random string is generated by the code above and the time
+ delta is small. */
+ v = 0;
+ for (i = 0; i < strlen (flag_random_seed); i++)
+ v = (v << 4) ^ (v >> (HOST_BITS_PER_WIDE_INT - 4)) ^ flag_random_seed[i];
template += strlen (template);
- v = value;
-
/* Fill in the random bits. */
template[0] = letters[v % 62];
v /= 62;
tree_code_name[TREE_CODE (node)], function, trim_filename (file), line);
}
+/* Similar to above, except that the check is for the bounds of a TREE_VEC's
+ (dynamically sized) vector. */
+
+void
+tree_vec_elt_check_failed (idx, len, file, line, function)
+ int idx;
+ int len;
+ const char *file;
+ int line;
+ const char *function;
+{
+ internal_error
+ ("tree check: accessed elt %d of tree_vec with %d elts in %s, at %s:%d",
+ idx + 1, len, function, trim_filename (file), line);
+}
+
+/* Similar to above, except that the check is for the bounds of the operand
+ vector of an expression node. */
+
+void
+tree_operand_check_failed (idx, code, file, line, function)
+ int idx;
+ enum tree_code code;
+ const char *file;
+ int line;
+ const char *function;
+{
+ internal_error
+ ("tree check: accessed operand %d of %s with %d operands in %s, at %s:%d",
+ idx + 1, tree_code_name[code], TREE_CODE_LENGTH (code),
+ function, trim_filename (file), line);
+}
#endif /* ENABLE_TREE_CHECKING */
\f
/* For a new vector type node T, build the information necessary for
- debuggint output. */
+ debugging output. */
static void
finish_vector_type (t)
unsigned_V4SI_type_node
= make_vector (V4SImode, unsigned_intSI_type_node, 1);
+ unsigned_V2HI_type_node
+ = make_vector (V2HImode, unsigned_intHI_type_node, 1);
unsigned_V2SI_type_node
= make_vector (V2SImode, unsigned_intSI_type_node, 1);
unsigned_V2DI_type_node
= make_vector (V8HImode, unsigned_intHI_type_node, 1);
unsigned_V16QI_type_node
= make_vector (V16QImode, unsigned_intQI_type_node, 1);
+ unsigned_V1DI_type_node
+ = make_vector (V1DImode, unsigned_intDI_type_node, 1);
V16SF_type_node = make_vector (V16SFmode, float_type_node, 0);
V4SF_type_node = make_vector (V4SFmode, float_type_node, 0);
V4SI_type_node = make_vector (V4SImode, intSI_type_node, 0);
+ V2HI_type_node = make_vector (V2HImode, intHI_type_node, 0);
V2SI_type_node = make_vector (V2SImode, intSI_type_node, 0);
V2DI_type_node = make_vector (V2DImode, intDI_type_node, 0);
V4HI_type_node = make_vector (V4HImode, intHI_type_node, 0);
V2SF_type_node = make_vector (V2SFmode, float_type_node, 0);
V2DF_type_node = make_vector (V2DFmode, double_type_node, 0);
V16QI_type_node = make_vector (V16QImode, intQI_type_node, 0);
+ V1DI_type_node = make_vector (V1DImode, intDI_type_node, 0);
}
/* Returns a vector tree node given a vector mode, the inner type, and
{
if (AGGREGATE_TYPE_P (TREE_TYPE (init)))
{
- tree aggr_init = TREE_OPERAND (init, 1);
+ tree aggr_init = CONSTRUCTOR_ELTS (init);
while (aggr_init)
{