/* 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"
#include "tm_p.h"
#include "function.h"
#include "obstack.h"
#include "target.h"
#include "langhooks.h"
-#define obstack_chunk_alloc xmalloc
-#define obstack_chunk_free free
/* 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
{
"lang_decl kinds",
"lang_type kinds"
};
+#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. */
-struct type_hash
+struct type_hash GTY(())
{
unsigned long hash;
tree type;
same table, they are completely independent, and the hash code is
computed differently for each of these. */
-htab_t type_hash_table;
+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 unsigned int type_hash_hash PARAMS ((const void*));
+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 type_hash_mark PARAMS ((const void *));
-static int mark_tree_hashtable_entry PARAMS((void **, void *));
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);
- ggc_add_deletable_htab (type_hash_table, type_hash_marked_p,
- type_hash_mark);
- ggc_add_tree_root (global_trees, TI_MAX);
- ggc_add_tree_root (integer_types, itk_none);
+ 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 ();
tree_node_kind kind;
#endif
struct tree_common ttmp;
-
+
/* We can't allocate a TREE_VEC without knowing how many elements
it will have. */
if (code == TREE_VEC)
abort ();
-
+
TREE_SET_CODE ((tree)&ttmp, code);
length = tree_size ((tree)&ttmp);
{
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++;
over1 |= TREE_OVERFLOW (value);
over2 |= TREE_CONSTANT_OVERFLOW (value);
}
-
+
TREE_OVERFLOW (v) = over1;
TREE_CONSTANT_OVERFLOW (v) = over2;
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 d;
{
tree v;
+ 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));
+ memcpy (dp, &d, sizeof (REAL_VALUE_TYPE));
+
TREE_TYPE (v) = type;
- TREE_REAL_CST (v) = d;
+ TREE_REAL_CST_PTR (v) = dp;
TREE_OVERFLOW (v) = TREE_CONSTANT_OVERFLOW (v) = overflow;
return v;
}
{
tree v;
int overflow = TREE_OVERFLOW (i);
- REAL_VALUE_TYPE d;
-
- v = make_node (REAL_CST);
- TREE_TYPE (v) = type;
- d = real_value_from_int_cst (type, i);
+ v = build_real (type, real_value_from_int_cst (type, i));
- /* Check for valid float value for this type on this target machine. */
-#ifdef CHECK_FLOAT_VALUE
- CHECK_FLOAT_VALUE (TYPE_MODE (type), d, overflow);
-#endif
-
- TREE_REAL_CST (v) = d;
- TREE_OVERFLOW (v) = TREE_CONSTANT_OVERFLOW (v) = overflow;
+ TREE_OVERFLOW (v) |= overflow;
+ TREE_CONSTANT_OVERFLOW (v) |= overflow;
return v;
}
int len;
{
tree t;
- int length = (len-1) * sizeof (tree) + sizeof (struct tree_vec);
+ int length = (len - 1) * sizeof (tree) + sizeof (struct tree_vec);
#ifdef GATHER_STATISTICS
- tree_node_counts[(int)vec_kind]++;
- tree_node_sizes[(int)vec_kind] += length;
+ tree_node_counts[(int) vec_kind]++;
+ tree_node_sizes[(int) vec_kind] += length;
#endif
t = ggc_alloc_tree (length);
|| (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. */
&& real_zerop (TREE_IMAGPART (expr))));
}
+/* Return 1 if EXPR is the real constant minus one. */
+
+int
+real_minus_onep (expr)
+ tree expr;
+{
+ STRIP_NOPS (expr);
+
+ return ((TREE_CODE (expr) == REAL_CST
+ && ! TREE_CONSTANT_OVERFLOW (expr)
+ && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconstm1))
+ || (TREE_CODE (expr) == COMPLEX_CST
+ && real_minus_onep (TREE_REALPART (expr))
+ && real_zerop (TREE_IMAGPART (expr))));
+}
+
/* Nonzero if EXP is a constant or a cast of a constant. */
int
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 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));
}
case FUNCTION_DECL:
/* Nested functions aren't static, since taking their address
involves a trampoline. */
- return (decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg))
- && ! DECL_NON_ADDR_CONST_P (arg);
+ return ((decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg))
+ && ! DECL_NON_ADDR_CONST_P (arg));
case VAR_DECL:
- return (TREE_STATIC (arg) || DECL_EXTERNAL (arg))
- && ! DECL_NON_ADDR_CONST_P (arg);
+ return ((TREE_STATIC (arg) || DECL_EXTERNAL (arg))
+ && ! DECL_THREAD_LOCAL (arg)
+ && ! DECL_NON_ADDR_CONST_P (arg));
case CONSTRUCTOR:
return TREE_STATIC (arg);
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 which tree structure is used by T. */
+
+enum tree_node_structure_enum
+tree_node_structure (t)
+ 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':
+ return TS_EXP;
+ default: /* 'c' and 'x' */
+ break;
+ }
+ switch (code)
+ {
+ /* 'c' cases. */
+ case INTEGER_CST: return TS_INT_CST;
+ case REAL_CST: return TS_REAL_CST;
+ case COMPLEX_CST: return TS_COMPLEX;
+ case VECTOR_CST: return TS_VECTOR;
+ case STRING_CST: return TS_STRING;
+ /* 'x' cases. */
+ case ERROR_MARK: return TS_COMMON;
+ case IDENTIFIER_NODE: return TS_IDENTIFIER;
+ case TREE_LIST: return TS_LIST;
+ case TREE_VEC: return TS_VEC;
+ case PLACEHOLDER_EXPR: return TS_COMMON;
+
+ default:
+ abort ();
+ }
+}
+
/* Perform any modifications to EXPR required when it is unsaved. Does
not recurse into EXPR's subtrees. */
{
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;
/* 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;
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
- if (TREE_CODE_CLASS (code) == '2'
+ if (TREE_CODE_CLASS (code) == '2'
|| TREE_CODE_CLASS (code) == '<'
|| TREE_CODE_LENGTH (code) != 1)
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
build_type_attribute_variant (ttype, attribute)
tree ttype, attribute;
{
- if ( ! attribute_list_equal (TYPE_ATTRIBUTES (ttype), attribute))
+ if (! attribute_list_equal (TYPE_ATTRIBUTES (ttype), attribute))
{
unsigned int hashcode;
tree ntype;
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;
{
return ggc_marked_p (type) || TYPE_SYMTAB_POINTER (type);
}
-/* Mark the entry in the type hash table the type it points to is marked.
- Also mark the type in case we are considering this entry "marked" by
- virtue of TYPE_SYMTAB_POINTER being set. */
-
-static void
-type_hash_mark (p)
- const void *p;
-{
- ggc_mark (p);
- ggc_mark_tree (((struct type_hash *) p)->type);
-}
-
-/* Mark the hashtable slot pointed to by ENTRY (which is really a
- `tree**') for GC. */
-
-static int
-mark_tree_hashtable_entry (entry, data)
- void **entry;
- void *data ATTRIBUTE_UNUSED;
-{
- ggc_mark_tree ((tree) *entry);
- return 1;
-}
-
-/* Mark ARG (which is really a htab_t whose slots are trees) for
- GC. */
-
-void
-mark_tree_hashtable (arg)
- void *arg;
-{
- htab_t t = *(htab_t *) arg;
- htab_traverse (t, mark_tree_hashtable_entry, 0);
-}
-
static void
print_type_hash_statistics ()
{
attribute_list_equal (l1, l2)
tree l1, l2;
{
- return attribute_list_contained (l1, l2)
- && attribute_list_contained (l2, l1);
+ return attribute_list_contained (l1, l2)
+ && attribute_list_contained (l2, l1);
}
/* Given two lists of attributes, return true if list L2 is
if (t1 == t2)
return 0;
- if (! TREE_UNSIGNED (TREE_TYPE (t1)))
+ if (TREE_UNSIGNED (TREE_TYPE (t1)) != TREE_UNSIGNED (TREE_TYPE (t2)))
+ {
+ int t1_sgn = tree_int_cst_sgn (t1);
+ int t2_sgn = tree_int_cst_sgn (t2);
+
+ if (t1_sgn < t2_sgn)
+ return 1;
+ else if (t1_sgn > t2_sgn)
+ return 0;
+ /* Otherwise, both are non-negative, so we compare them as
+ unsigned just in case one of them would overflow a signed
+ type. */
+ }
+ else if (! TREE_UNSIGNED (TREE_TYPE (t1)))
return INT_CST_LT (t1, t2);
return INT_CST_LT_UNSIGNED (t1, t2);
return -1;
else if (tree_int_cst_lt (t2, t1))
return 1;
- else
+ else
return 0;
}
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
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. */
return t;
}
+/* Build a function type. The RETURN_TYPE is the type retured 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 (tree return_type, ...)
+{
+ tree t, args, last;
+ va_list p;
+
+ va_start (p, return_type);
+
+ t = va_arg (p, tree);
+ for (args = NULL_TREE; t != NULL_TREE; t = va_arg (p, tree))
+ args = tree_cons (NULL_TREE, t, args);
+
+ last = args;
+ args = nreverse (args);
+ TREE_CHAIN (last) = void_list_node;
+ args = build_function_type (return_type, args);
+
+ 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.
/* 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. */
while (context)
{
+ if (TREE_CODE (context) == NAMESPACE_DECL)
+ return NULL_TREE;
+
if (TREE_CODE (context) == RECORD_TYPE
|| TREE_CODE (context) == UNION_TYPE
|| TREE_CODE (context) == QUAL_UNION_TYPE)
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_PREFIX_LEN 9
-
#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;
))
*p = '_';
}
-
+
/* Generate a name for a function unique to this translation unit.
TYPE is some string to identify the purpose of this function to the
linker or collect2. */
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 (V2DImode, unsigned_intDI_type_node, 1);
unsigned_V4HI_type_node
= make_vector (V4HImode, unsigned_intHI_type_node, 1);
unsigned_V8QI_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);
V8QI_type_node = make_vector (V8QImode, intQI_type_node, 0);
V8HI_type_node = make_vector (V8HImode, 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
case CONSTRUCTOR:
{
if (AGGREGATE_TYPE_P (TREE_TYPE (init)))
- {
- tree aggr_init = TREE_OPERAND (init, 1);
-
- while (aggr_init)
- {
- if (! initializer_zerop (TREE_VALUE (aggr_init)))
- return false;
- aggr_init = TREE_CHAIN (aggr_init);
- }
- return true;
- }
+ {
+ tree aggr_init = CONSTRUCTOR_ELTS (init);
+
+ while (aggr_init)
+ {
+ if (! initializer_zerop (TREE_VALUE (aggr_init)))
+ return false;
+ aggr_init = TREE_CHAIN (aggr_init);
+ }
+ return true;
+ }
return false;
}
default:
return false;
}
}
+
+#include "gt-tree.h"