/* 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.
#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. */
init_ttree ()
{
/* 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
+ 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) * sizeof (char *) - 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 ();
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
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 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 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,
bit_position (field)
tree field;
{
-
return bit_from_pos (DECL_FIELD_OFFSET (field),
DECL_FIELD_BIT_OFFSET (field));
}
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 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))
- ;
-
/* 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. */
/* 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
+bool
contains_placeholder_p (exp)
tree exp;
{
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 (type)
+ 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. */
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;
}
if (TREE_CODE_CLASS (code) == 's')
- {
- TREE_SIDE_EFFECTS (t) = 1;
- }
+ TREE_SIDE_EFFECTS (t) = 1;
else switch (code)
{
case INIT_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
abort ();
}
+/* Return the most significant bit of the integer constant T. */
+
+int
+tree_int_cst_msb (t)
+ tree t;
+{
+ int prec;
+ HOST_WIDE_INT h;
+ unsigned HOST_WIDE_INT l;
+
+ /* Note that using TYPE_PRECISION here is wrong. We care about the
+ actual bits, not the (arbitrary) range of the type. */
+ prec = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (t))) - 1;
+ rshift_double (TREE_INT_CST_LOW (t), TREE_INT_CST_HIGH (t), prec,
+ 2 * HOST_BITS_PER_WIDE_INT, &l, &h, 0);
+ return (l & 1) == 1;
+}
+
/* Return an indication of the sign of the integer constant T.
The return value is -1 if T < 0, 0 if T == 0, and 1 if T > 0.
Note that -1 will never be returned it T's type is unsigned. */
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);
+
+ 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
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);
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. */
\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;
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
{
if (AGGREGATE_TYPE_P (TREE_TYPE (init)))
{
- tree aggr_init = TREE_OPERAND (init, 1);
+ tree aggr_init = CONSTRUCTOR_ELTS (init);
while (aggr_init)
{