/* 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.
#include "langhooks.h"
/* obstack.[ch] explicitly declined to prototype this. */
-extern int _obstack_allocated_p PARAMS ((struct obstack *h, PTR obj));
+extern int _obstack_allocated_p (struct obstack *h, void *obj);
#ifdef GATHER_STATISTICS
/* Statistics-gathering stuff. */
-typedef enum
-{
- d_kind,
- t_kind,
- b_kind,
- s_kind,
- r_kind,
- e_kind,
- c_kind,
- id_kind,
- perm_list_kind,
- temp_list_kind,
- vec_kind,
- x_kind,
- lang_decl,
- lang_type,
- all_kinds
-} tree_node_kind;
int tree_node_counts[(int) all_kinds];
int tree_node_sizes[(int) all_kinds];
+/* Keep in sync with tree.h:enum tree_node_kind. */
static const char * const tree_node_kind_names[] = {
"decls",
"types",
#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 GTY ((if_marked ("type_hash_marked_p"), param_is (struct type_hash)))
htab_t type_hash_table;
-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 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));
-static int type_hash_marked_p PARAMS ((const void *));
+static void set_type_quals (tree, int);
+static int type_hash_eq (const void *, const void *);
+static hashval_t type_hash_hash (const void *);
+static void print_type_hash_statistics (void);
+static void finish_vector_type (tree);
+static tree make_vector (enum machine_mode, tree, int);
+static int type_hash_marked_p (const void *);
tree global_trees[TI_MAX];
tree integer_types[itk_none];
/* Init tree.c. */
void
-init_ttree ()
+init_ttree (void)
{
/* Initialize the hash table of types. */
type_hash_table = htab_create_ggc (TYPE_HASH_INITIAL_SIZE, type_hash_hash,
translations made by ASM_OUTPUT_LABELREF). Often this is the same
as DECL_NAME. It is an IDENTIFIER_NODE. */
tree
-decl_assembler_name (decl)
- tree decl;
+decl_assembler_name (tree decl)
{
if (!DECL_ASSEMBLER_NAME_SET_P (decl))
(*lang_hooks.set_decl_assembler_name) (decl);
/* 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
-tree_size (node)
- tree node;
+tree_size (tree node)
{
enum tree_code code = TREE_CODE (node);
Achoo! I got a code in the node. */
tree
-make_node (code)
- enum tree_code code;
+make_node (enum tree_code code)
{
tree t;
int type = TREE_CODE_CLASS (code);
t = ggc_alloc_tree (length);
- memset ((PTR) t, 0, length);
+ memset (t, 0, length);
TREE_SET_CODE (t, code);
DECL_ALIGN (t) = 1;
DECL_USER_ALIGN (t) = 0;
DECL_IN_SYSTEM_HEADER (t) = in_system_header;
- DECL_SOURCE_LINE (t) = lineno;
- DECL_SOURCE_FILE (t) =
- (input_filename) ? input_filename : "<built-in>";
+ DECL_SOURCE_LOCATION (t) = input_location;
DECL_UID (t) = next_decl_uid++;
/* We have not yet computed the alias set for this declaration. */
TREE_CHAIN is zero and it has a fresh uid. */
tree
-copy_node (node)
- tree node;
+copy_node (tree node)
{
tree t;
enum tree_code code = TREE_CODE (node);
For example, this can copy a list made of TREE_LIST nodes. */
tree
-copy_list (list)
- tree list;
+copy_list (tree list)
{
tree head;
tree prev, next;
This function should be used via the `build_int_2' macro. */
tree
-build_int_2_wide (low, hi)
- unsigned HOST_WIDE_INT low;
- HOST_WIDE_INT hi;
+build_int_2_wide (unsigned HOST_WIDE_INT low, HOST_WIDE_INT hi)
{
tree t = make_node (INTEGER_CST);
are in a list pointed by VALS. */
tree
-build_vector (type, vals)
- tree type, vals;
+build_vector (tree type, tree vals)
{
tree v = make_node (VECTOR_CST);
int over1 = 0, over2 = 0;
/* 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;
+build_constructor (tree type, tree vals)
{
tree c = make_node (CONSTRUCTOR);
TREE_TYPE (c) = type;
/* Return a new REAL_CST node whose type is TYPE and value is D. */
tree
-build_real (type, d)
- tree type;
- REAL_VALUE_TYPE d;
+build_real (tree type, REAL_VALUE_TYPE d)
{
tree v;
REAL_VALUE_TYPE *dp;
and whose value is the integer value of the INTEGER_CST node I. */
REAL_VALUE_TYPE
-real_value_from_int_cst (type, i)
- tree type ATTRIBUTE_UNUSED, i;
+real_value_from_int_cst (tree type, tree i)
{
REAL_VALUE_TYPE d;
/* Clear all bits of the real value type so that we can later do
bitwise comparisons to see if two values are the same. */
- memset ((char *) &d, 0, sizeof d);
+ memset (&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),
- TYPE_MODE (type));
- else
- REAL_VALUE_FROM_UNSIGNED_INT (d, TREE_INT_CST_LOW (i),
- TREE_INT_CST_HIGH (i), TYPE_MODE (type));
+ real_from_integer (&d, type ? TYPE_MODE (type) : VOIDmode,
+ TREE_INT_CST_LOW (i), TREE_INT_CST_HIGH (i),
+ TREE_UNSIGNED (TREE_TYPE (i)));
return d;
}
representing the same value as a floating-point constant of type TYPE. */
tree
-build_real_from_int_cst (type, i)
- tree type;
- tree i;
+build_real_from_int_cst (tree type, tree i)
{
tree v;
int overflow = TREE_OVERFLOW (i);
The TREE_TYPE is not initialized. */
tree
-build_string (len, str)
- int len;
- const char *str;
+build_string (int len, const char *str)
{
tree s = make_node (STRING_CST);
will be the type of the COMPLEX_CST; otherwise a new type will be made. */
tree
-build_complex (type, real, imag)
- tree type;
- tree real, imag;
+build_complex (tree type, tree real, tree imag)
{
tree t = make_node (COMPLEX_CST);
/* Build a newly constructed TREE_VEC node of length LEN. */
tree
-make_tree_vec (len)
- int len;
+make_tree_vec (int len)
{
tree t;
int length = (len - 1) * sizeof (tree) + sizeof (struct tree_vec);
t = ggc_alloc_tree (length);
- memset ((PTR) t, 0, length);
+ memset (t, 0, length);
TREE_SET_CODE (t, TREE_VEC);
TREE_VEC_LENGTH (t) = len;
of zero. */
int
-integer_zerop (expr)
- tree expr;
+integer_zerop (tree expr)
{
STRIP_NOPS (expr);
complex constant. */
int
-integer_onep (expr)
- tree expr;
+integer_onep (tree expr)
{
STRIP_NOPS (expr);
it contains. Likewise for the corresponding complex constant. */
int
-integer_all_onesp (expr)
- tree expr;
+integer_all_onesp (tree expr)
{
int prec;
int uns;
one bit on). */
int
-integer_pow2p (expr)
- tree expr;
+integer_pow2p (tree expr)
{
int prec;
HOST_WIDE_INT high, low;
complex constant other than zero. */
int
-integer_nonzerop (expr)
- tree expr;
+integer_nonzerop (tree expr)
{
STRIP_NOPS (expr);
power of two. */
int
-tree_log2 (expr)
- tree expr;
+tree_log2 (tree expr)
{
int prec;
HOST_WIDE_INT high, low;
than or equal to EXPR. */
int
-tree_floor_log2 (expr)
- tree expr;
+tree_floor_log2 (tree expr)
{
int prec;
HOST_WIDE_INT high, low;
/* Return 1 if EXPR is the real constant zero. */
int
-real_zerop (expr)
- tree expr;
+real_zerop (tree expr)
{
STRIP_NOPS (expr);
/* Return 1 if EXPR is the real constant one in real or complex form. */
int
-real_onep (expr)
- tree expr;
+real_onep (tree expr)
{
STRIP_NOPS (expr);
/* Return 1 if EXPR is the real constant two. */
int
-real_twop (expr)
- tree expr;
+real_twop (tree expr)
{
STRIP_NOPS (expr);
/* Return 1 if EXPR is the real constant minus one. */
int
-real_minus_onep (expr)
- tree expr;
+real_minus_onep (tree expr)
{
STRIP_NOPS (expr);
/* Nonzero if EXP is a constant or a cast of a constant. */
int
-really_constant_p (exp)
- tree exp;
+really_constant_p (tree exp)
{
/* This is not quite the same as STRIP_NOPS. It does more. */
while (TREE_CODE (exp) == NOP_EXPR
Return 0 if ELEM is not in LIST. */
tree
-value_member (elem, list)
- tree elem, list;
+value_member (tree elem, tree list)
{
while (list)
{
Return 0 if ELEM is not in LIST. */
tree
-purpose_member (elem, list)
- tree elem, list;
+purpose_member (tree elem, tree list)
{
while (list)
{
Return 0 if ELEM is not in LIST. */
tree
-binfo_member (elem, list)
- tree elem, list;
+binfo_member (tree elem, tree list)
{
while (list)
{
/* Return nonzero if ELEM is part of the chain CHAIN. */
int
-chain_member (elem, chain)
- tree elem, chain;
+chain_member (tree elem, tree chain)
{
while (chain)
{
This is the Lisp primitive `length'. */
int
-list_length (t)
- tree t;
+list_length (tree t)
{
tree tail;
int len = 0;
/* Returns the number of FIELD_DECLs in TYPE. */
int
-fields_length (type)
- tree type;
+fields_length (tree type)
{
tree t = TYPE_FIELDS (type);
int count = 0;
This is the Lisp primitive `nconc'. */
tree
-chainon (op1, op2)
- tree op1, op2;
+chainon (tree op1, tree 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). */
tree
-tree_last (chain)
- tree chain;
+tree_last (tree chain)
{
tree next;
if (chain)
and return the new head of the chain (old last element). */
tree
-nreverse (t)
- tree t;
+nreverse (tree t)
{
tree prev = 0, decl, next;
for (decl = t; decl; decl = next)
purpose and value fields are PARM and VALUE. */
tree
-build_tree_list (parm, value)
- tree parm, value;
+build_tree_list (tree parm, tree value)
{
tree t = make_node (TREE_LIST);
TREE_PURPOSE (t) = parm;
and whose TREE_CHAIN is CHAIN. */
tree
-tree_cons (purpose, value, chain)
- tree purpose, value, chain;
+tree_cons (tree purpose, tree value, tree chain)
{
tree node;
return node;
}
+/* Return the first expression in a sequence of COMPOUND_EXPRs. */
+
+tree
+expr_first (tree expr)
+{
+ if (expr == NULL_TREE)
+ return expr;
+ while (TREE_CODE (expr) == COMPOUND_EXPR)
+ expr = TREE_OPERAND (expr, 0);
+ return expr;
+}
+
+/* Return the last expression in a sequence of COMPOUND_EXPRs. */
+
+tree
+expr_last (tree expr)
+{
+ if (expr == NULL_TREE)
+ return expr;
+ while (TREE_CODE (expr) == COMPOUND_EXPR)
+ expr = TREE_OPERAND (expr, 1);
+ return expr;
+}
+
+/* Return the number of subexpressions in a sequence of COMPOUND_EXPRs. */
+
+int
+expr_length (tree expr)
+{
+ int len = 0;
+
+ if (expr == NULL_TREE)
+ return 0;
+ for (; TREE_CODE (expr) == COMPOUND_EXPR; expr = TREE_OPERAND (expr, 1))
+ len += expr_length (TREE_OPERAND (expr, 0));
+ ++len;
+ return len;
+}
\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,
make_unsigned_type). */
tree
-size_in_bytes (type)
- tree type;
+size_in_bytes (tree type)
{
tree t;
or return -1 if the size can vary or is larger than an integer. */
HOST_WIDE_INT
-int_size_in_bytes (type)
- tree type;
+int_size_in_bytes (tree type)
{
tree t;
This is a tree of type bitsizetype. */
tree
-bit_position (field)
- tree field;
+bit_position (tree field)
{
-
return bit_from_pos (DECL_FIELD_OFFSET (field),
DECL_FIELD_BIT_OFFSET (field));
}
of returning -1 like int_size_in_byte can. */
HOST_WIDE_INT
-int_bit_position (field)
- tree field;
+int_bit_position (tree field)
{
return tree_low_cst (bit_position (field), 0);
}
This is a tree of type sizetype. */
tree
-byte_position (field)
- tree field;
+byte_position (tree field)
{
return byte_from_pos (DECL_FIELD_OFFSET (field),
DECL_FIELD_BIT_OFFSET (field));
of returning -1 like int_size_in_byte can. */
HOST_WIDE_INT
-int_byte_position (field)
- tree field;
+int_byte_position (tree field)
{
return tree_low_cst (byte_position (field), 0);
}
/* Return the strictest alignment, in bits, that T is known to have. */
unsigned int
-expr_align (t)
- tree t;
+expr_align (tree t)
{
unsigned int align0, align1;
ARRAY_TYPE) minus one. This counts only elements of the top array. */
tree
-array_type_nelts (type)
- tree type;
+array_type_nelts (tree type)
{
tree index_type, min, max;
static storage. This is not the same as the C meaning of `static'. */
int
-staticp (arg)
- tree arg;
+staticp (tree arg)
{
switch (TREE_CODE (arg))
{
are used for. */
tree
-save_expr (expr)
- tree expr;
+save_expr (tree expr)
{
tree t = fold (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 actually occur. */
- inner = t;
- 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;
- }
-
/* 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)
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 (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 (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. */
tree
-unsave_expr (expr)
- tree expr;
+unsave_expr (tree expr)
{
tree t;
of operands if all are trees. */
int
-first_rtl_op (code)
- enum tree_code code;
+first_rtl_op (enum tree_code code)
{
switch (code)
{
return 0;
case WITH_CLEANUP_EXPR:
return 2;
- case METHOD_CALL_EXPR:
- return 3;
default:
return TREE_CODE_LENGTH (code);
}
/* Return which tree structure is used by T. */
enum tree_node_structure_enum
-tree_node_structure (t)
- tree t;
+tree_node_structure (tree t)
{
enum tree_code code = TREE_CODE (t);
-
+
switch (TREE_CODE_CLASS (code))
{
case 'd': return TS_DECL;
case 't': return TS_TYPE;
case 'b': return TS_BLOCK;
- case 'r': case '<': case '1': case '2': case 'e': case 's':
+ case 'r': case '<': case '1': case '2': case 'e': case 's':
return TS_EXP;
default: /* 'c' and 'x' */
break;
not recurse into EXPR's subtrees. */
void
-unsave_expr_1 (expr)
- tree expr;
+unsave_expr_1 (tree expr)
{
switch (TREE_CODE (expr))
{
/* Default lang hook for "unsave_expr_now". */
tree
-lhd_unsave_expr_now (expr)
- tree expr;
+lhd_unsave_expr_now (tree expr)
{
enum tree_code code;
never possible to unsave them. */
int
-unsafe_for_reeval (expr)
- tree expr;
+unsafe_for_reeval (tree expr)
{
int unsafeness = 0;
enum tree_code code;
/* Return 1 if EXP contains a PLACEHOLDER_EXPR; i.e., if it represents a size
or offset that depends on a field within a record. */
-int
-contains_placeholder_p (exp)
- tree exp;
+bool
+contains_placeholder_p (tree exp)
{
enum tree_code code;
int result;
position computations since they will be converted into a
WITH_RECORD_EXPR involving the reference, which will assume
here will be valid. */
- return contains_placeholder_p (TREE_OPERAND (exp, 0));
+ return CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 0));
case 'x':
if (code == TREE_LIST)
- return (contains_placeholder_p (TREE_VALUE (exp))
- || (TREE_CHAIN (exp) != 0
- && contains_placeholder_p (TREE_CHAIN (exp))));
+ return (CONTAINS_PLACEHOLDER_P (TREE_VALUE (exp))
+ || CONTAINS_PLACEHOLDER_P (TREE_CHAIN (exp)));
break;
case '1':
{
case COMPOUND_EXPR:
/* Ignoring the first operand isn't quite right, but works best. */
- return contains_placeholder_p (TREE_OPERAND (exp, 1));
+ return CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 1));
case RTL_EXPR:
case CONSTRUCTOR:
return 0;
case COND_EXPR:
- return (contains_placeholder_p (TREE_OPERAND (exp, 0))
- || contains_placeholder_p (TREE_OPERAND (exp, 1))
- || contains_placeholder_p (TREE_OPERAND (exp, 2)));
+ return (CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 0))
+ || CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 1))
+ || CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 2)));
case SAVE_EXPR:
/* If we already know this doesn't have a placeholder, don't
return 0;
SAVE_EXPR_NOPLACEHOLDER (exp) = 1;
- result = contains_placeholder_p (TREE_OPERAND (exp, 0));
+ result = CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 0));
if (result)
SAVE_EXPR_NOPLACEHOLDER (exp) = 0;
return result;
case CALL_EXPR:
- return (TREE_OPERAND (exp, 1) != 0
- && contains_placeholder_p (TREE_OPERAND (exp, 1)));
+ return CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 1));
default:
break;
switch (TREE_CODE_LENGTH (code))
{
case 1:
- return contains_placeholder_p (TREE_OPERAND (exp, 0));
+ return CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 0));
case 2:
- return (contains_placeholder_p (TREE_OPERAND (exp, 0))
- || contains_placeholder_p (TREE_OPERAND (exp, 1)));
+ return (CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 0))
+ || CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 1)));
default:
return 0;
}
return 0;
}
+/* Return 1 if any part of the computation of TYPE involves a PLACEHOLDER_EXPR.
+ This includes size, bounds, qualifiers (for QUAL_UNION_TYPE) and field
+ positions. */
+
+bool
+type_contains_placeholder_p (tree type)
+{
+ /* If the size contains a placeholder or the parent type (component type in
+ the case of arrays) type involves a placeholder, this type does. */
+ if (CONTAINS_PLACEHOLDER_P (TYPE_SIZE (type))
+ || CONTAINS_PLACEHOLDER_P (TYPE_SIZE_UNIT (type))
+ || (TREE_TYPE (type) != 0
+ && type_contains_placeholder_p (TREE_TYPE (type))))
+ return 1;
+
+ /* Now do type-specific checks. Note that the last part of the check above
+ greatly limits what we have to do below. */
+ switch (TREE_CODE (type))
+ {
+ case VOID_TYPE:
+ case COMPLEX_TYPE:
+ case VECTOR_TYPE:
+ case ENUMERAL_TYPE:
+ case BOOLEAN_TYPE:
+ case CHAR_TYPE:
+ case POINTER_TYPE:
+ case OFFSET_TYPE:
+ case REFERENCE_TYPE:
+ case METHOD_TYPE:
+ case FILE_TYPE:
+ case FUNCTION_TYPE:
+ return 0;
+
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ /* Here we just check the bounds. */
+ return (CONTAINS_PLACEHOLDER_P (TYPE_MIN_VALUE (type))
+ || CONTAINS_PLACEHOLDER_P (TYPE_MAX_VALUE (type)));
+
+ case ARRAY_TYPE:
+ case SET_TYPE:
+ /* We're already checked the component type (TREE_TYPE), so just check
+ the index type. */
+ return type_contains_placeholder_p (TYPE_DOMAIN (type));
+
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ {
+ static tree seen_types = 0;
+ tree field;
+ bool ret = 0;
+
+ /* We have to be careful here that we don't end up in infinite
+ recursions due to a field of a type being a pointer to that type
+ or to a mutually-recursive type. So we store a list of record
+ types that we've seen and see if this type is in them. To save
+ memory, we don't use a list for just one type. Here we check
+ whether we've seen this type before and store it if not. */
+ if (seen_types == 0)
+ seen_types = type;
+ else if (TREE_CODE (seen_types) != TREE_LIST)
+ {
+ if (seen_types == type)
+ return 0;
+
+ seen_types = tree_cons (NULL_TREE, type,
+ build_tree_list (NULL_TREE, seen_types));
+ }
+ else
+ {
+ if (value_member (type, seen_types) != 0)
+ return 0;
+
+ seen_types = tree_cons (NULL_TREE, type, seen_types);
+ }
+
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ if (TREE_CODE (field) == FIELD_DECL
+ && (CONTAINS_PLACEHOLDER_P (DECL_FIELD_OFFSET (field))
+ || (TREE_CODE (type) == QUAL_UNION_TYPE
+ && CONTAINS_PLACEHOLDER_P (DECL_QUALIFIER (field)))
+ || type_contains_placeholder_p (TREE_TYPE (field))))
+ {
+ ret = true;
+ break;
+ }
+
+ /* Now remove us from seen_types and return the result. */
+ if (seen_types == type)
+ seen_types = 0;
+ else
+ seen_types = TREE_CHAIN (seen_types);
+
+ return ret;
+ }
+
+ default:
+ abort ();
+ }
+}
+
/* Return 1 if EXP contains any expressions that produce cleanups for an
outer scope to deal with. Used by fold. */
int
-has_cleanups (exp)
- tree exp;
+has_cleanups (tree exp)
{
int i, nops, cmp;
PLACEHOLDER_EXPR occurring only in its arglist. */
tree
-substitute_in_expr (exp, f, r)
- tree exp;
- tree f;
- tree r;
+substitute_in_expr (tree exp, tree f, tree r)
{
enum tree_code code = TREE_CODE (exp);
tree op0, op1, op2;
op0 = TREE_OPERAND (exp, 0);
op1 = TREE_OPERAND (exp, 1);
- if (contains_placeholder_p (op0))
+ if (CONTAINS_PLACEHOLDER_P (op0))
op0 = substitute_in_expr (op0, f, r);
- if (contains_placeholder_p (op1))
+ if (CONTAINS_PLACEHOLDER_P (op1))
op1 = substitute_in_expr (op1, f, r);
if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1))
op1 = TREE_OPERAND (exp, 1);
op2 = TREE_OPERAND (exp, 2);
- if (contains_placeholder_p (op0))
+ if (CONTAINS_PLACEHOLDER_P (op0))
op0 = substitute_in_expr (op0, f, r);
- if (contains_placeholder_p (op1))
+ if (CONTAINS_PLACEHOLDER_P (op1))
op1 = substitute_in_expr (op1, f, r);
- if (contains_placeholder_p (op2))
+ if (CONTAINS_PLACEHOLDER_P (op2))
op2 = substitute_in_expr (op2, f, r);
if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1)
Any other kind of expression is returned unchanged. */
tree
-stabilize_reference (ref)
- tree ref;
+stabilize_reference (tree ref)
{
tree result;
enum tree_code code = TREE_CODE (ref);
multiple utterances of the same expression should that prove fruitful. */
tree
-stabilize_reference_1 (e)
- tree e;
+stabilize_reference_1 (tree e)
{
tree result;
enum tree_code code = TREE_CODE (e);
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;
+ tree node;
- 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;
+
+ if (code == CALL_EXPR && !TREE_SIDE_EFFECTS (t))
+ {
+ /* Calls have side-effects, except those to const or
+ pure functions. */
+ i = call_expr_flags (t);
+ if (!(i & (ECF_CONST | ECF_PURE)))
+ TREE_SIDE_EFFECTS (t) = 1;
+
+ /* And even those have side-effects if their arguments do. */
+ else for (node = TREE_OPERAND (t, 1); node; node = TREE_CHAIN (node))
+ if (TREE_SIDE_EFFECTS (TREE_VALUE (node)))
+ {
+ TREE_SIDE_EFFECTS (t) = 1;
+ break;
+ }
+ }
+
return t;
}
of varargs, which is expensive for RISC machines. */
tree
-build1 (code, type, node)
- enum tree_code code;
- tree type;
- tree node;
+build1 (enum tree_code code, tree type, tree node)
{
int length = sizeof (struct tree_exp);
#ifdef GATHER_STATISTICS
t = ggc_alloc_tree (length);
- memset ((PTR) t, 0, sizeof (struct tree_common));
+ memset (t, 0, sizeof (struct tree_common));
TREE_SET_CODE (t, code);
TREE_READONLY (t) = 0;
break;
+ case ADDR_EXPR:
+ if (node)
+ {
+ /* The address of a volatile decl or reference does not have
+ side-effects. But be careful not to ignore side-effects from
+ other sources deeper in the expression--if node is a _REF and
+ one of its operands has side-effects, so do we. */
+ if (TREE_THIS_VOLATILE (node))
+ {
+ TREE_SIDE_EFFECTS (t) = 0;
+ if (!DECL_P (node))
+ {
+ int i = first_rtl_op (TREE_CODE (node)) - 1;
+ for (; i >= 0; --i)
+ {
+ if (TREE_SIDE_EFFECTS (TREE_OPERAND (node, i)))
+ TREE_SIDE_EFFECTS (t) = 1;
+ }
+ }
+ }
+ }
+ break;
+
default:
if (TREE_CODE_CLASS (code) == '1' && node && TREE_CONSTANT (node))
TREE_CONSTANT (t) = 1;
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
Other slots are initialized to 0 or null pointers. */
tree
-build_decl (code, name, type)
- enum tree_code code;
- tree name, type;
+build_decl (enum tree_code code, tree name, tree type)
{
tree t;
compiled. This information is used for outputting debugging info. */
tree
-build_block (vars, tags, subblocks, supercontext, chain)
- tree vars, tags ATTRIBUTE_UNUSED, subblocks, supercontext, chain;
+build_block (tree vars, tree tags ATTRIBUTE_UNUSED, tree subblocks,
+ tree supercontext, tree chain)
{
tree block = make_node (BLOCK);
recursively more than one file (Java is one of them). */
tree
-build_expr_wfl (node, file, line, col)
- tree node;
- const char *file;
- int line, col;
+build_expr_wfl (tree node, const char *file, int line, int col)
{
static const char *last_file = 0;
static tree last_filenode = NULL_TREE;
is ATTRIBUTE. */
tree
-build_decl_attribute_variant (ddecl, attribute)
- tree ddecl, attribute;
+build_decl_attribute_variant (tree ddecl, tree attribute)
{
DECL_ATTRIBUTES (ddecl) = attribute;
return ddecl;
Record such modified types already made so we don't make duplicates. */
tree
-build_type_attribute_variant (ttype, attribute)
- tree ttype, attribute;
+build_type_attribute_variant (tree ttype, tree attribute)
{
if (! attribute_list_equal (TYPE_ATTRIBUTES (ttype), attribute))
{
their canonicalized form. */
int
-is_attribute_p (attr, ident)
- const char *attr;
- tree ident;
+is_attribute_p (const char *attr, tree ident)
{
int ident_len, attr_len;
const char *p;
be passed back in if further occurrences are wanted. */
tree
-lookup_attribute (attr_name, list)
- const char *attr_name;
- tree list;
+lookup_attribute (const char *attr_name, tree list)
{
tree l;
/* Return an attribute list that is the union of a1 and a2. */
tree
-merge_attributes (a1, a2)
- tree a1, a2;
+merge_attributes (tree a1, tree a2)
{
tree attributes;
the result. */
tree
-merge_type_attributes (t1, t2)
- tree t1, t2;
+merge_type_attributes (tree t1, tree t2)
{
return merge_attributes (TYPE_ATTRIBUTES (t1),
TYPE_ATTRIBUTES (t2));
the result. */
tree
-merge_decl_attributes (olddecl, newdecl)
- tree olddecl, newdecl;
+merge_decl_attributes (tree olddecl, tree newdecl)
{
return merge_attributes (DECL_ATTRIBUTES (olddecl),
DECL_ATTRIBUTES (newdecl));
The second instance of `foo' nullifies the dllimport. */
tree
-merge_dllimport_decl_attributes (old, new)
- tree old;
- tree new;
+merge_dllimport_decl_attributes (tree old, tree new)
{
tree a;
int delete_dllimport_p;
of the various TYPE_QUAL values. */
static void
-set_type_quals (type, type_quals)
- tree type;
- int type_quals;
+set_type_quals (tree type, int type_quals)
{
TYPE_READONLY (type) = (type_quals & TYPE_QUAL_CONST) != 0;
TYPE_VOLATILE (type) = (type_quals & TYPE_QUAL_VOLATILE) != 0;
return NULL_TREE. */
tree
-get_qualified_type (type, type_quals)
- tree type;
- int type_quals;
+get_qualified_type (tree type, int type_quals)
{
tree t;
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)
- && TYPE_CONTEXT (t) == TYPE_CONTEXT (type))
+ && TYPE_CONTEXT (t) == TYPE_CONTEXT (type)
+ && attribute_list_equal (TYPE_ATTRIBUTES (t), TYPE_ATTRIBUTES (type)))
return t;
return NULL_TREE;
exist. This function never returns NULL_TREE. */
tree
-build_qualified_type (type, type_quals)
- tree type;
- int type_quals;
+build_qualified_type (tree type, int type_quals)
{
tree t;
This is so the caller can modify it. */
tree
-build_type_copy (type)
- tree type;
+build_type_copy (tree type)
{
tree t, m = TYPE_MAIN_VARIANT (type);
of the individual types. */
unsigned int
-type_hash_list (list)
- tree list;
+type_hash_list (tree list)
{
unsigned int hashcode;
tree tail;
/* Returns true if the types are equal. */
static int
-type_hash_eq (va, vb)
- const void *va;
- const void *vb;
+type_hash_eq (const void *va, const void *vb)
{
const struct type_hash *a = va, *b = vb;
if (a->hash == b->hash
/* Return the cached hash value. */
static hashval_t
-type_hash_hash (item)
- const void *item;
+type_hash_hash (const void *item)
{
return ((const struct type_hash *) item)->hash;
}
If one is found, return it. Otherwise return 0. */
tree
-type_hash_lookup (hashcode, type)
- unsigned int hashcode;
- tree type;
+type_hash_lookup (unsigned int hashcode, tree type)
{
struct type_hash *h, in;
for a type TYPE whose hash code is HASHCODE. */
void
-type_hash_add (hashcode, type)
- unsigned int hashcode;
- tree type;
+type_hash_add (unsigned int hashcode, tree type)
{
struct type_hash *h;
void **loc;
- h = (struct type_hash *) ggc_alloc (sizeof (struct type_hash));
+ h = ggc_alloc (sizeof (struct type_hash));
h->hash = hashcode;
h->type = type;
loc = htab_find_slot_with_hash (type_hash_table, h, hashcode, INSERT);
int debug_no_type_hash = 0;
tree
-type_hash_canon (hashcode, type)
- unsigned int hashcode;
- tree type;
+type_hash_canon (unsigned int hashcode, tree type)
{
tree t1;
the number of garbage collections. */
static int
-type_hash_marked_p (p)
- const void *p;
+type_hash_marked_p (const void *p)
{
tree type = ((struct type_hash *) p)->type;
}
static void
-print_type_hash_statistics ()
+print_type_hash_statistics (void)
{
fprintf (stderr, "Type hash: size %ld, %ld elements, %f collisions\n",
(long) htab_size (type_hash_table),
by adding the hash codes of the individual attributes. */
unsigned int
-attribute_hash_list (list)
- tree list;
+attribute_hash_list (tree list)
{
unsigned int hashcode;
tree tail;
equivalent to l1. */
int
-attribute_list_equal (l1, l2)
- tree l1, l2;
+attribute_list_equal (tree l1, tree l2)
{
return attribute_list_contained (l1, l2)
&& attribute_list_contained (l2, l1);
correctly. */
int
-attribute_list_contained (l1, l2)
- tree l1, l2;
+attribute_list_contained (tree l1, tree l2)
{
tree t1, t2;
Also, the TREE_PURPOSEs must match. */
int
-type_list_equal (l1, l2)
- tree l1, l2;
+type_list_equal (tree l1, tree l2)
{
tree t1, t2;
then this function counts only the ordinary arguments. */
int
-type_num_arguments (type)
- tree type;
+type_num_arguments (tree type)
{
int i = 0;
tree t;
represent the same constant value. */
int
-tree_int_cst_equal (t1, t2)
- tree t1, t2;
+tree_int_cst_equal (tree t1, tree t2)
{
if (t1 == t2)
return 1;
The precise way of comparison depends on their data type. */
int
-tree_int_cst_lt (t1, t2)
- tree t1, t2;
+tree_int_cst_lt (tree t1, tree t2)
{
if (t1 == t2)
return 0;
/* Returns -1 if T1 < T2, 0 if T1 == T2, and 1 if T1 > T2. */
int
-tree_int_cst_compare (t1, t2)
- tree t1;
- tree t2;
+tree_int_cst_compare (tree t1, tree t2)
{
if (tree_int_cst_lt (t1, t2))
return -1;
be represented in a single unsigned HOST_WIDE_INT. */
int
-host_integerp (t, pos)
- tree t;
- int pos;
+host_integerp (tree t, int pos)
{
return (TREE_CODE (t) == INTEGER_CST
&& ! TREE_OVERFLOW (t)
be positive. Abort if we cannot satisfy the above conditions. */
HOST_WIDE_INT
-tree_low_cst (t, pos)
- tree t;
- int pos;
+tree_low_cst (tree t, int pos)
{
if (host_integerp (t, pos))
return TREE_INT_CST_LOW (t);
/* Return the most significant bit of the integer constant T. */
int
-tree_int_cst_msb (t)
- tree t;
+tree_int_cst_msb (tree t)
{
int prec;
HOST_WIDE_INT h;
Note that -1 will never be returned it T's type is unsigned. */
int
-tree_int_cst_sgn (t)
- tree t;
+tree_int_cst_sgn (tree t)
{
if (TREE_INT_CST_LOW (t) == 0 && TREE_INT_CST_HIGH (t) == 0)
return 0;
are known to be equal; otherwise return 0. */
int
-simple_cst_list_equal (l1, l2)
- tree l1, l2;
+simple_cst_list_equal (tree l1, tree l2)
{
while (l1 != NULL_TREE && l2 != NULL_TREE)
{
this function. */
int
-simple_cst_equal (t1, t2)
- tree t1, t2;
+simple_cst_equal (tree t1, tree t2)
{
enum tree_code code1, code2;
int cmp;
than U, respectively. */
int
-compare_tree_int (t, u)
- tree t;
- unsigned HOST_WIDE_INT u;
+compare_tree_int (tree t, unsigned HOST_WIDE_INT u)
{
if (tree_int_cst_sgn (t) < 0)
return -1;
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))
+ {
+ 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);
+
+ if (code == PLUS_EXPR || code == MULT_EXPR || code == MIN_EXPR
+ || code == MAX_EXPR || code == BIT_IOR_EXPR || code == BIT_XOR_EXPR
+ || code == BIT_AND_EXPR || code == NE_EXPR || code == EQ_EXPR)
+ {
+ /* It's a commutative expression. We want to hash it the same
+ however it appears. We do this by first hashing both operands
+ and then rehashing based on the order of their independent
+ hashes. */
+ hashval_t one = iterative_hash_expr (TREE_OPERAND (t, 0), 0);
+ hashval_t two = iterative_hash_expr (TREE_OPERAND (t, 1), 0);
+ hashval_t t;
+
+ if (one > two)
+ t = one, one = two, two = t;
+
+ val = iterative_hash_object (one, val);
+ val = iterative_hash_object (two, val);
+ }
+ else
+ 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
reuse it. */
tree
-build_pointer_type_for_mode (to_type, mode)
- tree to_type;
- enum machine_mode mode;
+build_pointer_type_for_mode (tree to_type, enum machine_mode mode)
{
tree t = TYPE_POINTER_TO (to_type);
/* By default build pointers in ptr_mode. */
tree
-build_pointer_type (to_type)
- tree to_type;
+build_pointer_type (tree to_type)
{
return build_pointer_type_for_mode (to_type, ptr_mode);
}
reuse it. */
tree
-build_reference_type_for_mode (to_type, mode)
- tree to_type;
- enum machine_mode mode;
+build_reference_type_for_mode (tree to_type, enum machine_mode mode)
{
tree t = TYPE_REFERENCE_TO (to_type);
in ptr_mode. */
tree
-build_reference_type (to_type)
- tree to_type;
+build_reference_type (tree to_type)
{
return build_reference_type_for_mode (to_type, ptr_mode);
}
const char *const *const * -> char ***. */
tree
-build_type_no_quals (t)
- tree t;
+build_type_no_quals (tree t)
{
switch (TREE_CODE (t))
{
sizes that use more than one HOST_WIDE_INT. */
tree
-build_index_type (maxval)
- tree maxval;
+build_index_type (tree maxval)
{
tree itype = make_node (INTEGER_TYPE);
if TYPE==NULL_TREE, sizetype is used. */
tree
-build_range_type (type, lowval, highval)
- tree type, lowval, highval;
+build_range_type (tree type, tree lowval, tree highval)
{
tree itype = make_node (INTEGER_TYPE);
of just highval (maxval). */
tree
-build_index_2_type (lowval, highval)
- tree lowval, highval;
+build_index_2_type (tree lowval, tree highval)
{
return build_range_type (sizetype, lowval, highval);
}
If such a type has already been constructed, reuse it. */
tree
-build_array_type (elt_type, index_type)
- tree elt_type, index_type;
+build_array_type (tree elt_type, tree index_type)
{
tree t;
unsigned int hashcode;
the innermost dimension of ARRAY. */
tree
-get_inner_array_type (array)
- tree array;
+get_inner_array_type (tree array)
{
tree type = TREE_TYPE (array);
If such a type has already been constructed, reuse it. */
tree
-build_function_type (value_type, arg_types)
- tree value_type, arg_types;
+build_function_type (tree value_type, tree arg_types)
{
tree t;
unsigned int hashcode;
return t;
}
-/* Build a function type. The RETURN_TYPE is the type retured by the
+/* Build a function type. The RETURN_TYPE is the type returned by the
function. If additional arguments are provided, they are
additional argument types. The list of argument types must always
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;
}
-/* Construct, lay out and return the type of methods belonging to class
- BASETYPE and whose arguments and values are described by TYPE.
- If that type exists already, reuse it.
- TYPE must be a FUNCTION_TYPE node. */
+/* Build a METHOD_TYPE for a member of BASETYPE. The RETTYPE (a TYPE)
+ and ARGTYPES (a TREE_LIST) are the return type and arguments types
+ for the method. An implicit additional parameter (of type
+ pointer-to-BASETYPE) is added to the ARGTYPES. */
tree
-build_method_type (basetype, type)
- tree basetype, type;
+build_method_type_directly (tree basetype,
+ tree rettype,
+ tree argtypes)
{
tree t;
- unsigned int hashcode;
+ tree ptype;
+ int hashcode;
/* Make a node of the sort we want. */
t = make_node (METHOD_TYPE);
- if (TREE_CODE (type) != FUNCTION_TYPE)
- abort ();
-
TYPE_METHOD_BASETYPE (t) = TYPE_MAIN_VARIANT (basetype);
- TREE_TYPE (t) = TREE_TYPE (type);
+ TREE_TYPE (t) = rettype;
+ ptype = build_pointer_type (basetype);
/* The actual arglist for this function includes a "hidden" argument
which is "this". Put it into the list of argument types. */
+ argtypes = tree_cons (NULL_TREE, ptype, argtypes);
+ TYPE_ARG_TYPES (t) = argtypes;
- TYPE_ARG_TYPES (t)
- = tree_cons (NULL_TREE,
- build_pointer_type (basetype), TYPE_ARG_TYPES (type));
+ /* If we already have such a type, use the old one and free this one.
+ Note that it also frees up the above cons cell if found. */
+ hashcode = TYPE_HASH (basetype) + TYPE_HASH (rettype) +
+ type_hash_list (argtypes);
- /* If we already have such a type, use the old one and free this one. */
- hashcode = TYPE_HASH (basetype) + TYPE_HASH (type);
t = type_hash_canon (hashcode, t);
if (!COMPLETE_TYPE_P (t))
return t;
}
+/* Construct, lay out and return the type of methods belonging to class
+ BASETYPE and whose arguments and values are described by TYPE.
+ If that type exists already, reuse it.
+ TYPE must be a FUNCTION_TYPE node. */
+
+tree
+build_method_type (tree basetype, tree type)
+{
+ if (TREE_CODE (type) != FUNCTION_TYPE)
+ abort ();
+
+ return build_method_type_directly (basetype,
+ TREE_TYPE (type),
+ TYPE_ARG_TYPES (type));
+}
+
/* Construct, lay out and return the type of offsets to a value
of type TYPE, within an object of type BASETYPE.
If a suitable offset type exists already, reuse it. */
tree
-build_offset_type (basetype, type)
- tree basetype, type;
+build_offset_type (tree basetype, tree type)
{
tree t;
unsigned int hashcode;
/* Create a complex type whose components are COMPONENT_TYPE. */
tree
-build_complex_type (component_type)
- tree component_type;
+build_complex_type (tree component_type)
{
tree t;
unsigned int hashcode;
is different from (int) OP. */
tree
-get_unwidened (op, for_type)
- tree op;
- tree for_type;
+get_unwidened (tree op, tree for_type)
{
/* Set UNS initially if converting OP to FOR_TYPE is a zero-extension. */
tree type = TREE_TYPE (op);
{
unsigned int innerprec
= tree_low_cst (DECL_SIZE (TREE_OPERAND (op, 1)), 1);
- int unsignedp = TREE_UNSIGNED (TREE_OPERAND (op, 1));
+ int unsignedp = (TREE_UNSIGNED (TREE_OPERAND (op, 1))
+ || TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op, 1))));
type = (*lang_hooks.types.type_for_size) (innerprec, unsignedp);
/* We can get this structure field in the narrowest type it fits in.
or 0 if the value should be sign-extended. */
tree
-get_narrower (op, unsignedp_ptr)
- tree op;
- int *unsignedp_ptr;
+get_narrower (tree op, int *unsignedp_ptr)
{
int uns = 0;
int first = 1;
{
unsigned HOST_WIDE_INT innerprec
= tree_low_cst (DECL_SIZE (TREE_OPERAND (op, 1)), 1);
- tree type = (*lang_hooks.types.type_for_size) (innerprec,
- TREE_UNSIGNED (op));
+ int unsignedp = (TREE_UNSIGNED (TREE_OPERAND (op, 1))
+ || TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op, 1))));
+ tree type = (*lang_hooks.types.type_for_size) (innerprec, unsignedp);
/* We can get this structure field in a narrower type that fits it,
but the resulting extension to its nominal type (a fullword type)
for type TYPE (an INTEGER_TYPE). */
int
-int_fits_type_p (c, type)
- tree c, type;
+int_fits_type_p (tree c, tree type)
{
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 (type)
&& TREE_UNSIGNED (TREE_TYPE (c)) && tree_int_cst_msb (c)))
return 0;
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)
{
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
{
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;
+variably_modified_type_p (tree type)
{
+ tree t;
+
if (type == error_mark_node)
return false;
- /* If TYPE itself has variable size, it is variably modified.
+ /* 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)
+ t = TYPE_SIZE (type);
+ if (t && t != error_mark_node && TREE_CODE (t) != 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)
+ switch (TREE_CODE (type))
{
- tree parm;
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ case ARRAY_TYPE:
+ /* If TYPE is a pointer or reference, it is variably modified if
+ the type pointed to is variably modified. Similarly for arrays;
+ note that VLAs are handled by the TYPE_SIZE check above. */
+ return variably_modified_type_p (TREE_TYPE (type));
+
+ case FUNCTION_TYPE:
+ case METHOD_TYPE:
+ /* If TYPE is a function type, it is variably modified if any of the
+ parameters or the return type are variably modified. */
+ {
+ 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)))
+ 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;
+ }
+ break;
+
+ case INTEGER_TYPE:
+ /* Scalar types are variably modified if their end points
+ aren't constant. */
+ t = TYPE_MIN_VALUE (type);
+ if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST)
+ return true;
+ t = TYPE_MAX_VALUE (type);
+ if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST)
+ return true;
+ return false;
+
+ default:
+ break;
}
/* The current language may have other cases to check, but in general,
NULL_TREE if there is no containing scope. */
tree
-get_containing_scope (t)
- tree t;
+get_containing_scope (tree t)
{
return (TYPE_P (t) ? TYPE_CONTEXT (t) : DECL_CONTEXT (t));
}
a FUNCTION_DECL, or zero if none. */
tree
-decl_function_context (decl)
- tree decl;
+decl_function_context (tree decl)
{
tree context;
TYPE_DECLs and FUNCTION_DECLs are transparent to this function. */
tree
-decl_type_context (decl)
- tree decl;
+decl_type_context (tree decl)
{
tree context = DECL_CONTEXT (decl);
while (context)
- {
- if (TREE_CODE (context) == NAMESPACE_DECL)
+ switch (TREE_CODE (context))
+ {
+ case NAMESPACE_DECL:
+ case TRANSLATION_UNIT_DECL:
return NULL_TREE;
- if (TREE_CODE (context) == RECORD_TYPE
- || TREE_CODE (context) == UNION_TYPE
- || TREE_CODE (context) == QUAL_UNION_TYPE)
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
return context;
-
- if (TREE_CODE (context) == TYPE_DECL
- || TREE_CODE (context) == FUNCTION_DECL)
+
+ case TYPE_DECL:
+ case FUNCTION_DECL:
context = DECL_CONTEXT (context);
-
- else if (TREE_CODE (context) == BLOCK)
+ break;
+
+ case BLOCK:
context = BLOCK_SUPERCONTEXT (context);
-
- else
- /* Unhandled CONTEXT!? */
+ break;
+
+ default:
abort ();
- }
+ }
+
return NULL_TREE;
}
determined. */
tree
-get_callee_fndecl (call)
- tree call;
+get_callee_fndecl (tree call)
{
tree addr;
if (TREE_CODE (addr) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (addr, 0)) == FUNCTION_DECL)
return TREE_OPERAND (addr, 0);
-
- /* We couldn't figure out what was being called. */
- return NULL_TREE;
+
+ /* We couldn't figure out what was being called. Maybe the front
+ end has some idea. */
+ return (*lang_hooks.lang_get_callee_fndecl) (call);
}
/* Print debugging information about tree nodes generated during the compile,
and any language-specific information. */
void
-dump_tree_statistics ()
+dump_tree_statistics (void)
{
#ifdef GATHER_STATISTICS
int i;
fprintf (stderr, "\n??? tree nodes created\n\n");
#ifdef GATHER_STATISTICS
- fprintf (stderr, "Kind Nodes Bytes\n");
- fprintf (stderr, "-------------------------------------\n");
+ fprintf (stderr, "Kind Nodes Bytes\n");
+ fprintf (stderr, "---------------------------------------\n");
total_nodes = total_bytes = 0;
for (i = 0; i < (int) all_kinds; i++)
{
- fprintf (stderr, "%-20s %6d %9d\n", tree_node_kind_names[i],
+ fprintf (stderr, "%-20s %7d %10d\n", tree_node_kind_names[i],
tree_node_counts[i], tree_node_sizes[i]);
total_nodes += tree_node_counts[i];
total_bytes += tree_node_sizes[i];
}
- fprintf (stderr, "-------------------------------------\n");
- fprintf (stderr, "%-20s %6d %9d\n", "Total", total_nodes, total_bytes);
- fprintf (stderr, "-------------------------------------\n");
+ fprintf (stderr, "---------------------------------------\n");
+ fprintf (stderr, "%-20s %7d %10d\n", "Total", total_nodes, total_bytes);
+ fprintf (stderr, "---------------------------------------\n");
#else
fprintf (stderr, "(No per-node statistics)\n");
#endif
\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. */
+/* Generate a crc32 of a string. */
-void
-default_flag_random_seed (void)
+unsigned
+crc32_string (unsigned chksum, const char *string)
{
- 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.
-
- Derived from mkstemp.c in libiberty. */
-
-static void
-append_random_chars (template)
- char *template;
-{
- static const char letters[]
- = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- unsigned HOST_WIDE_INT v;
- size_t i;
-
- default_flag_random_seed ();
-
- /* 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);
-
- /* Fill in the random bits. */
- template[0] = letters[v % 62];
- v /= 62;
- template[1] = letters[v % 62];
- v /= 62;
- template[2] = letters[v % 62];
- v /= 62;
- template[3] = letters[v % 62];
- v /= 62;
- template[4] = letters[v % 62];
- v /= 62;
- template[5] = letters[v % 62];
-
- template[6] = '\0';
+ do
+ {
+ unsigned value = *string << 24;
+ unsigned ix;
+
+ for (ix = 8; ix--; value <<= 1)
+ {
+ unsigned feedback;
+
+ feedback = (value ^ chksum) & 0x80000000 ? 0x04c11db7 : 0;
+ chksum <<= 1;
+ chksum ^= feedback;
+ }
+ }
+ while (*string++);
+ return chksum;
}
/* P is a string that will be used in a symbol. Mask out any characters
that are not valid in that context. */
void
-clean_symbol_name (p)
- char *p;
+clean_symbol_name (char *p)
{
for (; *p; p++)
if (! (ISALNUM (*p)
linker or collect2. */
tree
-get_file_function_name_long (type)
- const char *type;
+get_file_function_name_long (const char *type)
{
char *buf;
const 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. */
-
+ unsigned len;
const char *name = weak_global_object_name;
const char *file = main_input_filename;
if (! file)
file = input_filename;
- q = (char *) alloca (7 + strlen (name) + strlen (file));
+ len = strlen (file);
+ q = alloca (9 * 2 + len + 1);
+ memcpy (q, file, len + 1);
+ clean_symbol_name (q);
+
+ sprintf (q + len, "_%08X_%08X", crc32_string (0, name),
+ crc32_string (0, flag_random_seed));
- sprintf (q, "%s%s", name, file);
- append_random_chars (q);
p = q;
}
- buf = (char *) alloca (sizeof (FILE_FUNCTION_FORMAT) + strlen (p)
- + strlen (type));
+ buf = alloca (sizeof (FILE_FUNCTION_FORMAT) + strlen (p) + strlen (type));
/* Set up the name of the file-level functions we may need.
Use a global object (which is already required to be unique over
constraints). */
sprintf (buf, FILE_FUNCTION_FORMAT, type, p);
- /* Don't need to pull weird characters out of global names. */
- if (p != first_global_object_name)
- clean_symbol_name (buf + 11);
-
return get_identifier (buf);
}
If KIND=='D', return a suitable global clean-up (destructor) name. */
tree
-get_file_function_name (kind)
- int kind;
+get_file_function_name (int kind)
{
char p[2];
Otherwise, a TREE_LIST of the non-constant elements is emitted. */
tree
-get_set_constructor_bits (init, buffer, bit_size)
- tree init;
- char *buffer;
- int bit_size;
+get_set_constructor_bits (tree init, char *buffer, int bit_size)
{
int i;
tree vals;
Otherwise, a TREE_LIST of the non-constant elements is emitted. */
tree
-get_set_constructor_bytes (init, buffer, wd_size)
- tree init;
- unsigned char *buffer;
- int wd_size;
+get_set_constructor_bytes (tree init, unsigned char *buffer, int wd_size)
{
int i;
int set_word_size = BITS_PER_UNIT;
int bit_size = wd_size * set_word_size;
int bit_pos = 0;
unsigned char *bytep = buffer;
- char *bit_buffer = (char *) alloca (bit_size);
+ char *bit_buffer = alloca (bit_size);
tree non_const_bits = get_set_constructor_bits (init, bit_buffer, bit_size);
for (i = 0; i < wd_size; i++)
FILE, LINE, and FUNCTION are of the caller. */
void
-tree_check_failed (node, code, file, line, function)
- const tree node;
- enum tree_code code;
- const char *file;
- int line;
- const char *function;
+tree_check_failed (const tree node, enum tree_code code, const char *file,
+ int line, const char *function)
{
internal_error ("tree check: expected %s, have %s in %s, at %s:%d",
tree_code_name[code], tree_code_name[TREE_CODE (node)],
code, given in CL. */
void
-tree_class_check_failed (node, cl, file, line, function)
- const tree node;
- int cl;
- const char *file;
- int line;
- const char *function;
+tree_class_check_failed (const tree node, int cl, const char *file,
+ int line, const char *function)
{
internal_error
("tree check: expected class '%c', have '%c' (%s) in %s, at %s:%d",
(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;
+tree_vec_elt_check_failed (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",
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;
+tree_operand_check_failed (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",
debugging output. */
static void
-finish_vector_type (t)
- tree t;
+finish_vector_type (tree t)
{
layout_type (t);
this function to select one of the types as sizetype. */
void
-build_common_tree_nodes (signed_char)
- int signed_char;
+build_common_tree_nodes (int signed_char)
{
error_mark_node = make_node (ERROR_MARK);
TREE_TYPE (error_mark_node) = error_mark_node;
long_long_integer_type_node = make_signed_type (LONG_LONG_TYPE_SIZE);
long_long_unsigned_type_node = make_unsigned_type (LONG_LONG_TYPE_SIZE);
+ /* Define a boolean type. This type only represents boolean values but
+ may be larger than char depending on the value of BOOL_TYPE_SIZE.
+ Front ends which want to override this size (i.e. Java) can redefine
+ boolean_type_node before calling build_common_tree_nodes_2. */
+ boolean_type_node = make_unsigned_type (BOOL_TYPE_SIZE);
+ TREE_SET_CODE (boolean_type_node, BOOLEAN_TYPE);
+ TYPE_MAX_VALUE (boolean_type_node) = build_int_2 (1, 0);
+ TREE_TYPE (TYPE_MAX_VALUE (boolean_type_node)) = boolean_type_node;
+ TYPE_PRECISION (boolean_type_node) = 1;
+
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));
It will create several other common tree nodes. */
void
-build_common_tree_nodes_2 (short_double)
- int short_double;
+build_common_tree_nodes_2 (int short_double)
{
/* Define these next since types below may used them. */
integer_zero_node = build_int_2 (0, 0);
bitsize_one_node = bitsize_int (1);
bitsize_unit_node = bitsize_int (BITS_PER_UNIT);
+ boolean_false_node = TYPE_MIN_VALUE (boolean_type_node);
+ boolean_true_node = TYPE_MAX_VALUE (boolean_type_node);
+
void_type_node = make_node (VOID_TYPE);
layout_type (void_type_node);
TYPE_PRECISION (long_double_type_node) = LONG_DOUBLE_TYPE_SIZE;
layout_type (long_double_type_node);
+ float_ptr_type_node = build_pointer_type (float_type_node);
+ double_ptr_type_node = build_pointer_type (double_type_node);
+ long_double_ptr_type_node = build_pointer_type (long_double_type_node);
+ integer_ptr_type_node = build_pointer_type (integer_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);
layout_type (complex_long_double_type_node);
{
- tree t;
- BUILD_VA_LIST_TYPE (t);
+ tree t = (*targetm.build_builtin_va_list) ();
- /* Many back-ends define record types without seting TYPE_NAME.
+ /* Many back-ends define record types without setting TYPE_NAME.
If we copied the record type here, we'd keep the original
record type without a name. This breaks name mangling. So,
don't copy record types and let c_common_nodes_and_builtins()
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);
+ V4DF_type_node = make_vector (V4DFmode, double_type_node, 0);
}
/* Returns a vector tree node given a vector mode, the inner type, and
the signness. */
static tree
-make_vector (mode, innertype, unsignedp)
- enum machine_mode mode;
- tree innertype;
- int unsignedp;
+make_vector (enum machine_mode mode, tree innertype, int unsignedp)
{
tree t;
aggregate of zeros. Otherwise return FALSE. */
bool
-initializer_zerop (init)
- tree init;
+initializer_zerop (tree init)
{
STRIP_NOPS (init);