/* 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, 2003 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GCC.
#include "output.h"
#include "target.h"
#include "langhooks.h"
+#include "tree-iterator.h"
+#include "basic-block.h"
+#include "tree-flow.h"
/* obstack.[ch] explicitly declined to prototype this. */
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",
"perm_tree_lists",
"temp_tree_lists",
"vecs",
+ "phi_nodes",
+ "ssa names",
"random kinds",
"lang_decl kinds",
"lang_type kinds"
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 *);
+static unsigned int type_hash_list (tree, hashval_t);
+static unsigned int attribute_hash_list (tree, hashval_t);
tree global_trees[TI_MAX];
tree integer_types[itk_none];
decl_assembler_name (tree decl)
{
if (!DECL_ASSEMBLER_NAME_SET_P (decl))
- (*lang_hooks.set_decl_assembler_name) (decl);
+ lang_hooks.set_decl_assembler_name (decl);
return DECL_CHECK (decl)->decl.assembler_name;
}
case VECTOR_CST: return sizeof (struct tree_vector);
case STRING_CST: return sizeof (struct tree_string);
default:
- return (*lang_hooks.tree_size) (code);
+ return lang_hooks.tree_size (code);
}
case 'x': /* something random, like an identifier. */
case ERROR_MARK:
case PLACEHOLDER_EXPR: return sizeof (struct tree_common);
+ case PHI_NODE: return (sizeof (struct tree_phi_node)
+ + (PHI_ARG_CAPACITY (node) - 1) *
+ sizeof (struct phi_arg_d));
+
+ case EPHI_NODE: return (sizeof (struct tree_ephi_node)
+ + (EPHI_ARG_CAPACITY (node) - 1) *
+ sizeof (struct ephi_arg_d));
+
+ case SSA_NAME: return sizeof (struct tree_ssa_name);
+ case EUSE_NODE: return sizeof (struct tree_euse_node);
+
+ case EKILL_NODE:
+ case EEXIT_NODE: return sizeof (struct tree_eref_common);
+
+ case STATEMENT_LIST: return sizeof (struct tree_statement_list);
+
default:
- return (*lang_hooks.tree_size) (code);
+ return lang_hooks.tree_size (code);
}
default:
Achoo! I got a code in the node. */
tree
-make_node (enum tree_code code)
+make_node_stat (enum tree_code code MEM_STAT_DECL)
{
tree t;
int type = TREE_CODE_CLASS (code);
#endif
struct tree_common ttmp;
- /* We can't allocate a TREE_VEC without knowing how many elements
- it will have. */
- if (code == TREE_VEC)
+ /* We can't allocate a TREE_VEC, PHI_NODE, EPHI_NODE or STRING_CST
+ without knowing how many elements it will have. */
+ if (code == TREE_VEC || code == PHI_NODE || code == EPHI_NODE)
abort ();
TREE_SET_CODE ((tree)&ttmp, code);
kind = id_kind;
else if (code == TREE_VEC)
kind = vec_kind;
+ else if (code == PHI_NODE)
+ kind = phi_kind;
+ else if (code == SSA_NAME)
+ kind = ssa_name_kind;
else
kind = x_kind;
break;
tree_node_sizes[(int) kind] += length;
#endif
- t = ggc_alloc_tree (length);
+ t = ggc_alloc_zone_stat (length, tree_zone PASS_MEM_STAT);
memset (t, 0, length);
/* Default to no attributes for type, but let target change that. */
TYPE_ATTRIBUTES (t) = NULL_TREE;
- (*targetm.set_default_type_attributes) (t);
+ targetm.set_default_type_attributes (t);
/* We have not yet computed the alias set for this type. */
TYPE_ALIAS_SET (t) = -1;
case 'c':
TREE_CONSTANT (t) = 1;
+ TREE_INVARIANT (t) = 1;
break;
case 'e':
TREE_CHAIN is zero and it has a fresh uid. */
tree
-copy_node (tree node)
+copy_node_stat (tree node MEM_STAT_DECL)
{
tree t;
enum tree_code code = TREE_CODE (node);
size_t length;
+#ifdef ENABLE_CHECKING
+ if (code == STATEMENT_LIST)
+ abort ();
+#endif
+
length = tree_size (node);
- t = ggc_alloc_tree (length);
+ t = ggc_alloc_zone_stat (length, tree_zone PASS_MEM_STAT);
memcpy (t, node, length);
TREE_CHAIN (t) = 0;
TREE_ASM_WRITTEN (t) = 0;
+ TREE_VISITED (t) = 0;
+ t->common.ann = 0;
if (TREE_CODE_CLASS (code) == 'd')
DECL_UID (t) = next_decl_uid++;
TREE_SIDE_EFFECTS (c) = TREE_SIDE_EFFECTS (vals);
TREE_READONLY (c) = TREE_READONLY (vals);
TREE_CONSTANT (c) = TREE_CONSTANT (vals);
+ TREE_INVARIANT (c) = TREE_INVARIANT (vals);
}
- else
- TREE_CONSTANT (c) = 0; /* safe side */
return c;
}
and whose value is the integer value of the INTEGER_CST node I. */
REAL_VALUE_TYPE
-real_value_from_int_cst (tree type ATTRIBUTE_UNUSED, tree 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),
+ TYPE_UNSIGNED (TREE_TYPE (i)));
return d;
}
/* Build a newly constructed TREE_VEC node of length LEN. */
tree
-make_tree_vec (int len)
+make_tree_vec_stat (int len MEM_STAT_DECL)
{
tree t;
int length = (len - 1) * sizeof (tree) + sizeof (struct tree_vec);
tree_node_sizes[(int) vec_kind] += length;
#endif
- t = ggc_alloc_tree (length);
+ t = ggc_alloc_zone_stat (length, tree_zone PASS_MEM_STAT);
memset (t, 0, length);
+
TREE_SET_CODE (t, TREE_VEC);
TREE_VEC_LENGTH (t) = len;
|| TREE_CONSTANT_OVERFLOW (expr))
return 0;
- uns = TREE_UNSIGNED (TREE_TYPE (expr));
+ uns = TYPE_UNSIGNED (TREE_TYPE (expr));
if (!uns)
return (TREE_INT_CST_LOW (expr) == ~(unsigned HOST_WIDE_INT) 0
&& TREE_INT_CST_HIGH (expr) == -1);
int
list_length (tree t)
{
- tree tail;
+ tree p = t;
+#ifdef ENABLE_TREE_CHECKING
+ tree q = t;
+#endif
int len = 0;
- for (tail = t; tail; tail = TREE_CHAIN (tail))
- len++;
+ while (p)
+ {
+ p = TREE_CHAIN (p);
+#ifdef ENABLE_TREE_CHECKING
+ if (len % 2)
+ q = TREE_CHAIN (q);
+ if (p == q)
+ abort ();
+#endif
+ len++;
+ }
return len;
}
purpose and value fields are PARM and VALUE. */
tree
-build_tree_list (tree parm, tree value)
+build_tree_list_stat (tree parm, tree value MEM_STAT_DECL)
{
- tree t = make_node (TREE_LIST);
+ tree t = make_node_stat (TREE_LIST PASS_MEM_STAT);
TREE_PURPOSE (t) = parm;
TREE_VALUE (t) = value;
return t;
and whose TREE_CHAIN is CHAIN. */
tree
-tree_cons (tree purpose, tree value, tree chain)
+tree_cons_stat (tree purpose, tree value, tree chain MEM_STAT_DECL)
{
tree node;
- node = ggc_alloc_tree (sizeof (struct tree_list));
+ node = ggc_alloc_zone_stat (sizeof (struct tree_list),
+ tree_zone PASS_MEM_STAT);
memset (node, 0, sizeof (struct tree_common));
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,
if (t == 0)
{
- (*lang_hooks.types.incomplete_type_error) (NULL_TREE, type);
+ lang_hooks.types.incomplete_type_error (NULL_TREE, type);
return size_zero_node;
}
case SAVE_EXPR: case COMPOUND_EXPR: case MODIFY_EXPR:
case INIT_EXPR: case TARGET_EXPR: case WITH_CLEANUP_EXPR:
- case WITH_RECORD_EXPR: case CLEANUP_POINT_EXPR: case UNSAVE_EXPR:
+ case CLEANUP_POINT_EXPR: case UNSAVE_EXPR:
/* These don't change the alignment of an object. */
return expr_align (TREE_OPERAND (t, 0));
case STRING_CST:
return 1;
+ case COMPONENT_REF:
+ /* If the thing being referenced is not a field, then it is
+ something language specific. */
+ if (TREE_CODE (TREE_OPERAND (arg, 1)) != FIELD_DECL)
+ return (*lang_hooks.staticp) (arg);
+
/* If we are referencing a bitfield, we can't evaluate an
ADDR_EXPR at compile time and so it isn't a constant. */
- case COMPONENT_REF:
- return (! DECL_BIT_FIELD (TREE_OPERAND (arg, 1))
- && staticp (TREE_OPERAND (arg, 0)));
+ if (DECL_BIT_FIELD (TREE_OPERAND (arg, 1)))
+ return 0;
+
+ return staticp (TREE_OPERAND (arg, 0));
case BIT_FIELD_REF:
return 0;
if (TREE_CODE (TYPE_SIZE (TREE_TYPE (arg))) == INTEGER_CST
&& TREE_CODE (TREE_OPERAND (arg, 1)) == INTEGER_CST)
return staticp (TREE_OPERAND (arg, 0));
+ else
+ return 0;
default:
if ((unsigned int) TREE_CODE (arg)
>= (unsigned int) LAST_AND_UNUSED_TREE_CODE)
- return (*lang_hooks.staticp) (arg);
+ return lang_hooks.staticp (arg);
else
return 0;
}
Since it is no problem to reevaluate literals, we just return the
literal node. */
inner = skip_simple_arithmetic (t);
- if (TREE_CONSTANT (inner)
+
+ if (TREE_INVARIANT (inner)
|| (TREE_READONLY (inner) && ! TREE_SIDE_EFFECTS (inner))
|| TREE_CODE (inner) == SAVE_EXPR
|| TREE_CODE (inner) == ERROR_MARK)
eliminated as dead. */
TREE_SIDE_EFFECTS (t) = 1;
TREE_READONLY (t) = 1;
+ TREE_INVARIANT (t) = 1;
return t;
}
inner = TREE_OPERAND (inner, 0);
else if (TREE_CODE_CLASS (TREE_CODE (inner)) == '2')
{
- if (TREE_CONSTANT (TREE_OPERAND (inner, 1)))
+ if (TREE_INVARIANT (TREE_OPERAND (inner, 1)))
inner = TREE_OPERAND (inner, 0);
- else if (TREE_CONSTANT (TREE_OPERAND (inner, 0)))
+ else if (TREE_INVARIANT (TREE_OPERAND (inner, 0)))
inner = TREE_OPERAND (inner, 1);
else
break;
return 0;
case WITH_CLEANUP_EXPR:
return 2;
- case METHOD_CALL_EXPR:
- return 3;
default:
return TREE_CODE_LENGTH (code);
}
case IDENTIFIER_NODE: return TS_IDENTIFIER;
case TREE_LIST: return TS_LIST;
case TREE_VEC: return TS_VEC;
+ case PHI_NODE: return TS_PHI_NODE;
+ case EPHI_NODE: return TS_EPHI_NODE;
+ case EUSE_NODE: return TS_EUSE_NODE;
+ case EKILL_NODE: return TS_EREF_NODE;
+ case EEXIT_NODE: return TS_EREF_NODE;
+ case SSA_NAME: return TS_SSA_NAME;
case PLACEHOLDER_EXPR: return TS_COMMON;
+ case STATEMENT_LIST: return TS_STATEMENT_LIST;
default:
abort ();
}
}
-/* Default lang hook for "unsave_expr_now". */
-
-tree
-lhd_unsave_expr_now (tree expr)
-{
- enum tree_code code;
-
- /* There's nothing to do for NULL_TREE. */
- if (expr == 0)
- return expr;
-
- unsave_expr_1 (expr);
-
- code = TREE_CODE (expr);
- switch (TREE_CODE_CLASS (code))
- {
- case 'c': /* a constant */
- case 't': /* a type node */
- case 'd': /* A decl node */
- case 'b': /* A block node */
- break;
-
- case 'x': /* miscellaneous: e.g., identifier, TREE_LIST or ERROR_MARK. */
- if (code == TREE_LIST)
- {
- lhd_unsave_expr_now (TREE_VALUE (expr));
- lhd_unsave_expr_now (TREE_CHAIN (expr));
- }
- break;
-
- case 'e': /* an expression */
- case 'r': /* a reference */
- case 's': /* an expression with side effects */
- case '<': /* a comparison expression */
- case '2': /* a binary arithmetic expression */
- case '1': /* a unary arithmetic expression */
- {
- int i;
-
- for (i = first_rtl_op (code) - 1; i >= 0; i--)
- lhd_unsave_expr_now (TREE_OPERAND (expr, i));
- }
- break;
-
- default:
- abort ();
- }
-
- return expr;
-}
-
/* Return 0 if it is safe to evaluate EXPR multiple times,
return 1 if it is safe if EXPR is unsaved afterward, or
return 2 if it is completely unsafe.
case RTL_EXPR:
return 2;
+ /* A label can only be emitted once. */
+ case LABEL_EXPR:
+ return 1;
+
+ case BIND_EXPR:
+ unsafeness = 1;
+ break;
+
case TREE_LIST:
for (exp = expr; exp != 0; exp = TREE_CHAIN (exp))
{
unsafeness = 1;
break;
+ case EXIT_BLOCK_EXPR:
+ /* EXIT_BLOCK_LABELED_BLOCK, a.k.a. TREE_OPERAND (expr, 0), holds
+ a reference to an ancestor LABELED_BLOCK, so we need to avoid
+ unbounded recursion in the 'e' traversal code below. */
+ exp = EXIT_BLOCK_RETURN (expr);
+ return exp ? unsafe_for_reeval (exp) : 0;
+
default:
- tmp = (*lang_hooks.unsafe_for_reeval) (expr);
+ tmp = lang_hooks.unsafe_for_reeval (expr);
if (tmp >= 0)
return tmp;
break;
if (!exp)
return 0;
- /* If we have a WITH_RECORD_EXPR, it "cancels" any PLACEHOLDER_EXPR
- in it since it is supplying a value for it. */
code = TREE_CODE (exp);
- if (code == WITH_RECORD_EXPR)
- return 0;
- else if (code == PLACEHOLDER_EXPR)
+ if (code == PLACEHOLDER_EXPR)
return 1;
switch (TREE_CODE_CLASS (code))
/* Ignoring the first operand isn't quite right, but works best. */
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))
return result;
- case CALL_EXPR:
- return CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 1));
-
default:
break;
}
- switch (TREE_CODE_LENGTH (code))
+ switch (first_rtl_op (code))
{
case 1:
return CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 0));
{
case VOID_TYPE:
case COMPLEX_TYPE:
- case VECTOR_TYPE:
case ENUMERAL_TYPE:
case BOOLEAN_TYPE:
case CHAR_TYPE:
case ARRAY_TYPE:
case SET_TYPE:
+ case VECTOR_TYPE:
/* We're already checked the component type (TREE_TYPE), so just check
the index type. */
return type_contains_placeholder_p (TYPE_DOMAIN (type));
tree new;
tree inner;
- switch (TREE_CODE_CLASS (code))
+ /* We handle TREE_LIST and COMPONENT_REF separately. */
+ if (code == TREE_LIST)
{
- case 'c':
- case 'd':
- return exp;
-
- case 'x':
- if (code == PLACEHOLDER_EXPR)
+ op0 = SUBSTITUTE_IN_EXPR (TREE_CHAIN (exp), f, r);
+ op1 = SUBSTITUTE_IN_EXPR (TREE_VALUE (exp), f, r);
+ if (op0 == TREE_CHAIN (exp) && op1 == TREE_VALUE (exp))
return exp;
- else if (code == TREE_LIST)
- {
- op0 = (TREE_CHAIN (exp) == 0
- ? 0 : substitute_in_expr (TREE_CHAIN (exp), f, r));
- op1 = substitute_in_expr (TREE_VALUE (exp), f, r);
- if (op0 == TREE_CHAIN (exp) && op1 == TREE_VALUE (exp))
- return exp;
-
- return tree_cons (TREE_PURPOSE (exp), op1, op0);
- }
- abort ();
+ return tree_cons (TREE_PURPOSE (exp), op1, op0);
+ }
+ else if (code == COMPONENT_REF)
+ {
+ /* If this expression is getting a value from a PLACEHOLDER_EXPR
+ and it is the right field, replace it with R. */
+ for (inner = TREE_OPERAND (exp, 0);
+ TREE_CODE_CLASS (TREE_CODE (inner)) == 'r';
+ inner = TREE_OPERAND (inner, 0))
+ ;
+ if (TREE_CODE (inner) == PLACEHOLDER_EXPR
+ && TREE_OPERAND (exp, 1) == f)
+ return r;
+
+ /* If this expression hasn't been completed let, leave it
+ alone. */
+ if (TREE_CODE (inner) == PLACEHOLDER_EXPR && TREE_TYPE (inner) == 0)
+ return exp;
+
+ op0 = SUBSTITUTE_IN_EXPR (TREE_OPERAND (exp, 0), f, r);
+ if (op0 == TREE_OPERAND (exp, 0))
+ return exp;
+
+ new = fold (build (code, TREE_TYPE (exp), op0, TREE_OPERAND (exp, 1)));
+ }
+ else
+ switch (TREE_CODE_CLASS (code))
+ {
+ case 'c':
+ case 'd':
+ return exp;
- case '1':
- case '2':
- case '<':
- case 'e':
- switch (TREE_CODE_LENGTH (code))
- {
- case 1:
- op0 = substitute_in_expr (TREE_OPERAND (exp, 0), f, r);
- if (op0 == TREE_OPERAND (exp, 0))
+ case 'x':
+ case '1':
+ case '2':
+ case '<':
+ case 'e':
+ case 'r':
+ switch (first_rtl_op (code))
+ {
+ case 0:
return exp;
- if (code == NON_LVALUE_EXPR)
- return op0;
-
- new = fold (build1 (code, TREE_TYPE (exp), op0));
- break;
+ case 1:
+ op0 = SUBSTITUTE_IN_EXPR (TREE_OPERAND (exp, 0), f, r);
+ if (op0 == TREE_OPERAND (exp, 0))
+ return exp;
- case 2:
- /* An RTL_EXPR cannot contain a PLACEHOLDER_EXPR; a CONSTRUCTOR
- could, but we don't support it. */
- if (code == RTL_EXPR)
- return exp;
- else if (code == CONSTRUCTOR)
- abort ();
+ new = fold (build1 (code, TREE_TYPE (exp), op0));
+ break;
- 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);
+ case 2:
+ op0 = SUBSTITUTE_IN_EXPR (TREE_OPERAND (exp, 0), f, r);
+ op1 = SUBSTITUTE_IN_EXPR (TREE_OPERAND (exp, 1), f, r);
- if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1))
- return exp;
+ if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1))
+ return exp;
- new = fold (build (code, TREE_TYPE (exp), op0, op1));
- break;
+ new = fold (build2 (code, TREE_TYPE (exp), op0, op1));
+ break;
- case 3:
- /* It cannot be that anything inside a SAVE_EXPR contains a
- PLACEHOLDER_EXPR. */
- if (code == SAVE_EXPR)
- return exp;
+ case 3:
+ 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);
- else if (code == CALL_EXPR)
- {
- op1 = substitute_in_expr (TREE_OPERAND (exp, 1), f, r);
- if (op1 == TREE_OPERAND (exp, 1))
- return exp;
+ if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1)
+ && op2 == TREE_OPERAND (exp, 2))
+ return exp;
- return build (code, TREE_TYPE (exp),
- TREE_OPERAND (exp, 0), op1, NULL_TREE);
- }
+ new = fold (build3 (code, TREE_TYPE (exp), op0, op1, op2));
+ break;
- else if (code != COND_EXPR)
+ default:
abort ();
+ }
+ break;
- 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;
-
- new = fold (build (code, TREE_TYPE (exp), op0, op1, op2));
- break;
-
- default:
- abort ();
- }
+ default:
+ abort ();
+ }
- break;
+ TREE_READONLY (new) = TREE_READONLY (exp);
+ return new;
+}
- case 'r':
- switch (code)
- {
- case COMPONENT_REF:
- /* If this expression is getting a value from a PLACEHOLDER_EXPR
- and it is the right field, replace it with R. */
- for (inner = TREE_OPERAND (exp, 0);
- TREE_CODE_CLASS (TREE_CODE (inner)) == 'r';
- inner = TREE_OPERAND (inner, 0))
- ;
- if (TREE_CODE (inner) == PLACEHOLDER_EXPR
- && TREE_OPERAND (exp, 1) == f)
- return r;
-
- /* If this expression hasn't been completed let, leave it
- alone. */
- if (TREE_CODE (inner) == PLACEHOLDER_EXPR
- && TREE_TYPE (inner) == 0)
- return exp;
+/* Similar, but look for a PLACEHOLDER_EXPR in EXP and find a replacement
+ for it within OBJ, a tree that is an object or a chain of references. */
- op0 = substitute_in_expr (TREE_OPERAND (exp, 0), f, r);
- if (op0 == TREE_OPERAND (exp, 0))
- return exp;
+tree
+substitute_placeholder_in_expr (tree exp, tree obj)
+{
+ enum tree_code code = TREE_CODE (exp);
+ tree op0, op1, op2, op3;
- new = fold (build (code, TREE_TYPE (exp), op0,
- TREE_OPERAND (exp, 1)));
- break;
+ /* If this is a PLACEHOLDER_EXPR, see if we find a corresponding type
+ in the chain of OBJ. */
+ if (code == PLACEHOLDER_EXPR)
+ {
+ tree need_type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
+ tree elt;
+
+ for (elt = obj; elt != 0;
+ elt = ((TREE_CODE (elt) == COMPOUND_EXPR
+ || TREE_CODE (elt) == COND_EXPR)
+ ? TREE_OPERAND (elt, 1)
+ : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
+ ? TREE_OPERAND (elt, 0) : 0))
+ if (TYPE_MAIN_VARIANT (TREE_TYPE (elt)) == need_type)
+ return elt;
+
+ for (elt = obj; elt != 0;
+ elt = ((TREE_CODE (elt) == COMPOUND_EXPR
+ || TREE_CODE (elt) == COND_EXPR)
+ ? TREE_OPERAND (elt, 1)
+ : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
+ ? TREE_OPERAND (elt, 0) : 0))
+ if (POINTER_TYPE_P (TREE_TYPE (elt))
+ && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (elt)))
+ == need_type))
+ return fold (build1 (INDIRECT_REF, need_type, elt));
+
+ /* If we didn't find it, return the original PLACEHOLDER_EXPR. If it
+ survives until RTL generation, there will be an error. */
+ return exp;
+ }
- case BIT_FIELD_REF:
- 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);
- if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1)
- && op2 == TREE_OPERAND (exp, 2))
- return exp;
+ /* TREE_LIST is special because we need to look at TREE_VALUE
+ and TREE_CHAIN, not TREE_OPERANDS. */
+ else if (code == TREE_LIST)
+ {
+ op0 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_CHAIN (exp), obj);
+ op1 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_VALUE (exp), obj);
+ if (op0 == TREE_CHAIN (exp) && op1 == TREE_VALUE (exp))
+ return exp;
- new = fold (build (code, TREE_TYPE (exp), op0, op1, op2));
- break;
+ return tree_cons (TREE_PURPOSE (exp), op1, op0);
+ }
+ else
+ switch (TREE_CODE_CLASS (code))
+ {
+ case 'c':
+ case 'd':
+ case 'b':
+ return exp;
- case INDIRECT_REF:
- case BUFFER_REF:
- op0 = substitute_in_expr (TREE_OPERAND (exp, 0), f, r);
- if (op0 == TREE_OPERAND (exp, 0))
+ case 'x':
+ case '1':
+ case '2':
+ case '<':
+ case 'e':
+ case 'r':
+ case 's':
+ switch (first_rtl_op (code))
+ {
+ case 0:
return exp;
- new = fold (build1 (code, TREE_TYPE (exp), op0));
- break;
-
- default:
- abort ();
- }
- break;
-
- default:
- abort ();
- }
+ case 1:
+ op0 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 0), obj);
+ if (op0 == TREE_OPERAND (exp, 0))
+ return exp;
+ else
+ return fold (build1 (code, TREE_TYPE (exp), op0));
+
+ case 2:
+ op0 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 0), obj);
+ op1 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 1), obj);
+
+ if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1))
+ return exp;
+ else
+ return fold (build2 (code, TREE_TYPE (exp), op0, op1));
+
+ case 3:
+ op0 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 0), obj);
+ op1 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 1), obj);
+ op2 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 2), obj);
+
+ if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1)
+ && op2 == TREE_OPERAND (exp, 2))
+ return exp;
+ else
+ return fold (build3 (code, TREE_TYPE (exp), op0, op1, op2));
+
+ case 4:
+ op0 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 0), obj);
+ op1 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 1), obj);
+ op2 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 2), obj);
+ op3 = SUBSTITUTE_PLACEHOLDER_IN_EXPR (TREE_OPERAND (exp, 3), obj);
+
+ if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1)
+ && op2 == TREE_OPERAND (exp, 2)
+ && op3 == TREE_OPERAND (exp, 3))
+ return exp;
+ else
+ return fold (build4 (code, TREE_TYPE (exp), op0, op1, op2, op3));
+
+ default:
+ abort ();
+ }
+ break;
- TREE_READONLY (new) = TREE_READONLY (exp);
- return new;
+ default:
+ abort ();
+ }
}
\f
/* Stabilize a reference so that we can use it any number of times
ignore things that are actual constant or that already have been
handled by this function. */
- if (TREE_CONSTANT (e) || code == SAVE_EXPR)
+ if (TREE_INVARIANT (e))
return e;
switch (TREE_CODE_CLASS (code))
TREE_READONLY (result) = TREE_READONLY (e);
TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (e);
TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e);
+ TREE_INVARIANT (result) = 1;
return result;
}
\f
/* Low-level constructors for expressions. */
-/* Build an expression of code CODE, data type TYPE,
- and operands as specified by the arguments ARG1 and following arguments.
- Expressions and reference nodes can be created this way.
- Constants, decls, types and misc nodes cannot be. */
+/* A helper function for build1 and constant folders.
+ Set TREE_CONSTANT and TREE_INVARIANT for an ADDR_EXPR. */
-tree
-build (enum tree_code code, tree tt, ...)
+void
+recompute_tree_invarant_for_addr_expr (tree t)
{
- tree t;
- int length;
- int i;
- int fro;
- int constant;
- va_list p;
-
- va_start (p, tt);
-
- t = make_node (code);
- length = TREE_CODE_LENGTH (code);
- TREE_TYPE (t) = tt;
-
- /* Below, we automatically set TREE_SIDE_EFFECTS and TREE_READONLY for the
- result based on those same flags for the arguments. But if the
- arguments aren't really even `tree' expressions, we shouldn't be trying
- to do this. */
- fro = first_rtl_op (code);
+ tree node = TREE_OPERAND (t, 0);
+ bool tc = false, ti = false;
- /* Expressions without side effects may be constant if their
- arguments are as well. */
- constant = (TREE_CODE_CLASS (code) == '<'
- || TREE_CODE_CLASS (code) == '1'
- || TREE_CODE_CLASS (code) == '2'
- || TREE_CODE_CLASS (code) == 'c');
-
- if (length == 2)
+ /* Addresses of constants and static variables are constant;
+ all other decl addresses are invariant. */
+ if (staticp (node))
+ tc = ti = true;
+ else
{
- /* This is equivalent to the loop below, but faster. */
- tree arg0 = va_arg (p, tree);
- tree arg1 = va_arg (p, tree);
-
- TREE_OPERAND (t, 0) = arg0;
- TREE_OPERAND (t, 1) = arg1;
- TREE_READONLY (t) = 1;
- if (arg0 && fro > 0)
- {
- if (TREE_SIDE_EFFECTS (arg0))
- TREE_SIDE_EFFECTS (t) = 1;
- if (!TREE_READONLY (arg0))
- TREE_READONLY (t) = 0;
- if (!TREE_CONSTANT (arg0))
- constant = 0;
- }
-
- if (arg1 && fro > 1)
+ /* Step past constant offsets. */
+ while (1)
{
- if (TREE_SIDE_EFFECTS (arg1))
- TREE_SIDE_EFFECTS (t) = 1;
- if (!TREE_READONLY (arg1))
- TREE_READONLY (t) = 0;
- if (!TREE_CONSTANT (arg1))
- constant = 0;
+ if (TREE_CODE (node) == COMPONENT_REF
+ && TREE_CODE (TREE_OPERAND (node, 1)) == FIELD_DECL
+ && ! DECL_BIT_FIELD (TREE_OPERAND (node, 1)))
+ ;
+ else if (TREE_CODE (node) == ARRAY_REF
+ && TREE_CONSTANT (TREE_OPERAND (node, 1)))
+ ;
+ else
+ break;
+ node = TREE_OPERAND (node, 0);
}
+ if (DECL_P (node))
+ ti = true;
}
- else if (length == 1)
- {
- tree arg0 = va_arg (p, tree);
- /* The only one-operand cases we handle here are those with side-effects.
- Others are handled with build1. So don't bother checked if the
- arg has side-effects since we'll already have set it.
+ TREE_CONSTANT (t) = tc;
+ TREE_INVARIANT (t) = ti;
+}
- ??? This really should use build1 too. */
- if (TREE_CODE_CLASS (code) != 's')
- abort ();
- TREE_OPERAND (t, 0) = arg0;
- }
- else
- {
- for (i = 0; i < length; i++)
- {
- tree operand = va_arg (p, tree);
+/* Build an expression of code CODE, data type TYPE, and operands as
+ specified. Expressions and reference nodes can be created this way.
+ Constants, decls, types and misc nodes cannot be.
- TREE_OPERAND (t, i) = operand;
- if (operand && fro > i)
- {
- if (TREE_SIDE_EFFECTS (operand))
- TREE_SIDE_EFFECTS (t) = 1;
- if (!TREE_CONSTANT (operand))
- constant = 0;
- }
- }
- }
- va_end (p);
+ We define 5 non-variadic functions, from 0 to 4 arguments. This is
+ enough for all extant tree codes. These functions can be called
+ directly (preferably!), but can also be obtained via GCC preprocessor
+ magic within the build macro. */
+
+tree
+build0_stat (enum tree_code code, tree tt MEM_STAT_DECL)
+{
+ tree t;
+
+#ifdef ENABLE_CHECKING
+ if (TREE_CODE_LENGTH (code) != 0)
+ abort ();
+#endif
+
+ t = make_node_stat (code PASS_MEM_STAT);
+ TREE_TYPE (t) = tt;
- TREE_CONSTANT (t) = constant;
return t;
}
-/* Same as above, but only builds for unary operators.
- Saves lions share of calls to `build'; cuts down use
- of varargs, which is expensive for RISC machines. */
-
tree
-build1 (enum tree_code code, tree type, tree node)
+build1_stat (enum tree_code code, tree type, tree node MEM_STAT_DECL)
{
int length = sizeof (struct tree_exp);
#ifdef GATHER_STATISTICS
#endif
#ifdef ENABLE_CHECKING
- if (TREE_CODE_CLASS (code) == '2'
- || TREE_CODE_CLASS (code) == '<'
- || TREE_CODE_LENGTH (code) != 1)
+ if (TREE_CODE_LENGTH (code) != 1)
abort ();
#endif /* ENABLE_CHECKING */
- t = ggc_alloc_tree (length);
+ t = ggc_alloc_zone_stat (length, tree_zone PASS_MEM_STAT);
memset (t, 0, sizeof (struct tree_common));
TREE_SET_CODE (t, code);
TREE_TYPE (t) = type;
+ SET_EXPR_LOCUS (t, NULL);
TREE_COMPLEXITY (t) = 0;
TREE_OPERAND (t, 0) = node;
- if (node && first_rtl_op (code) != 0)
+ TREE_BLOCK (t) = NULL_TREE;
+ if (node && !TYPE_P (node) && first_rtl_op (code) != 0)
{
TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (node);
TREE_READONLY (t) = TREE_READONLY (node);
TREE_READONLY (t) = 0;
break;
- default:
- if (TREE_CODE_CLASS (code) == '1' && node && TREE_CONSTANT (node))
- TREE_CONSTANT (t) = 1;
- break;
- }
+ case ADDR_EXPR:
+ if (node)
+ {
+ recompute_tree_invarant_for_addr_expr (t);
+
+ /* 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 && !TYPE_P (node)
+ && TREE_CONSTANT (node))
+ TREE_CONSTANT (t) = 1;
+ if (TREE_CODE_CLASS (code) == '1' && node && TREE_INVARIANT (node))
+ TREE_INVARIANT (t) = 1;
+ break;
+ }
+
+ return t;
+}
+
+#define PROCESS_ARG(N) \
+ do { \
+ TREE_OPERAND (t, N) = arg##N; \
+ if (arg##N &&!TYPE_P (arg##N) && fro > N) \
+ { \
+ if (TREE_SIDE_EFFECTS (arg##N)) \
+ side_effects = 1; \
+ if (!TREE_READONLY (arg##N)) \
+ read_only = 0; \
+ if (!TREE_CONSTANT (arg##N)) \
+ constant = 0; \
+ if (!TREE_INVARIANT (arg##N)) \
+ invariant = 0; \
+ } \
+ } while (0)
+
+tree
+build2_stat (enum tree_code code, tree tt, tree arg0, tree arg1 MEM_STAT_DECL)
+{
+ bool constant, read_only, side_effects, invariant;
+ tree t;
+ int fro;
+
+#ifdef ENABLE_CHECKING
+ if (TREE_CODE_LENGTH (code) != 2)
+ abort ();
+#endif
+
+ t = make_node_stat (code PASS_MEM_STAT);
+ TREE_TYPE (t) = tt;
+
+ /* Below, we automatically set TREE_SIDE_EFFECTS and TREE_READONLY for the
+ result based on those same flags for the arguments. But if the
+ arguments aren't really even `tree' expressions, we shouldn't be trying
+ to do this. */
+ fro = first_rtl_op (code);
+
+ /* Expressions without side effects may be constant if their
+ arguments are as well. */
+ constant = (TREE_CODE_CLASS (code) == '<'
+ || TREE_CODE_CLASS (code) == '2');
+ read_only = 1;
+ side_effects = TREE_SIDE_EFFECTS (t);
+ invariant = constant;
+
+ PROCESS_ARG(0);
+ PROCESS_ARG(1);
+
+ TREE_READONLY (t) = read_only;
+ TREE_CONSTANT (t) = constant;
+ TREE_INVARIANT (t) = invariant;
+ TREE_SIDE_EFFECTS (t) = side_effects;
+
+ return t;
+}
+
+tree
+build3_stat (enum tree_code code, tree tt, tree arg0, tree arg1,
+ tree arg2 MEM_STAT_DECL)
+{
+ bool constant, read_only, side_effects, invariant;
+ tree t;
+ int fro;
+
+#ifdef ENABLE_CHECKING
+ if (TREE_CODE_LENGTH (code) != 3)
+ abort ();
+#endif
+
+ t = make_node_stat (code PASS_MEM_STAT);
+ TREE_TYPE (t) = tt;
+
+ fro = first_rtl_op (code);
+
+ side_effects = TREE_SIDE_EFFECTS (t);
+
+ PROCESS_ARG(0);
+ PROCESS_ARG(1);
+ PROCESS_ARG(2);
+
+ if (code == CALL_EXPR && !side_effects)
+ {
+ tree node;
+ int i;
+
+ /* Calls have side-effects, except those to const or
+ pure functions. */
+ i = call_expr_flags (t);
+ if (!(i & (ECF_CONST | ECF_PURE)))
+ side_effects = 1;
+
+ /* And even those have side-effects if their arguments do. */
+ else for (node = arg1; node; node = TREE_CHAIN (node))
+ if (TREE_SIDE_EFFECTS (TREE_VALUE (node)))
+ {
+ side_effects = 1;
+ break;
+ }
+ }
+
+ TREE_SIDE_EFFECTS (t) = side_effects;
+
+ return t;
+}
+
+tree
+build4_stat (enum tree_code code, tree tt, tree arg0, tree arg1,
+ tree arg2, tree arg3 MEM_STAT_DECL)
+{
+ bool constant, read_only, side_effects, invariant;
+ tree t;
+ int fro;
+
+#ifdef ENABLE_CHECKING
+ if (TREE_CODE_LENGTH (code) != 4)
+ abort ();
+#endif
+
+ t = make_node_stat (code PASS_MEM_STAT);
+ TREE_TYPE (t) = tt;
+
+ fro = first_rtl_op (code);
+
+ side_effects = TREE_SIDE_EFFECTS (t);
+
+ PROCESS_ARG(0);
+ PROCESS_ARG(1);
+ PROCESS_ARG(2);
+ PROCESS_ARG(3);
+
+ TREE_SIDE_EFFECTS (t) = side_effects;
+
+ return t;
+}
+
+/* Backup definition for non-gcc build compilers. */
+
+tree
+(build) (enum tree_code code, tree tt, ...)
+{
+ tree t, arg0, arg1, arg2, arg3;
+ int length = TREE_CODE_LENGTH (code);
+ va_list p;
+
+ va_start (p, tt);
+ switch (length)
+ {
+ case 0:
+ t = build0 (code, tt);
+ break;
+ case 1:
+ arg0 = va_arg (p, tree);
+ t = build1 (code, tt, arg0);
+ break;
+ case 2:
+ arg0 = va_arg (p, tree);
+ arg1 = va_arg (p, tree);
+ t = build2 (code, tt, arg0, arg1);
+ break;
+ case 3:
+ arg0 = va_arg (p, tree);
+ arg1 = va_arg (p, tree);
+ arg2 = va_arg (p, tree);
+ t = build3 (code, tt, arg0, arg1, arg2);
+ break;
+ case 4:
+ arg0 = va_arg (p, tree);
+ arg1 = va_arg (p, tree);
+ arg2 = va_arg (p, tree);
+ arg3 = va_arg (p, tree);
+ t = build4 (code, tt, arg0, arg1, arg2, arg3);
+ break;
+ default:
+ abort ();
+ }
+ va_end (p);
return t;
}
Other slots are initialized to 0 or null pointers. */
tree
-build_decl (enum tree_code code, tree name, tree type)
+build_decl_stat (enum tree_code code, tree name, tree type MEM_STAT_DECL)
{
tree t;
- t = make_node (code);
+ t = make_node_stat (code PASS_MEM_STAT);
/* if (type == error_mark_node)
type = integer_type_node; */
return block;
}
-/* EXPR_WITH_FILE_LOCATION are used to keep track of the exact
- location where an expression or an identifier were encountered. It
- is necessary for languages where the frontend parser will handle
- recursively more than one file (Java is one of them). */
+static GTY(()) tree last_annotated_node;
-tree
-build_expr_wfl (tree node, const char *file, int line, int col)
-{
- static const char *last_file = 0;
- static tree last_filenode = NULL_TREE;
- tree wfl = make_node (EXPR_WITH_FILE_LOCATION);
+/* Record the exact location where an expression or an identifier were
+ encountered. */
- EXPR_WFL_NODE (wfl) = node;
- EXPR_WFL_SET_LINECOL (wfl, line, col);
- if (file != last_file)
+void
+annotate_with_file_line (tree node, const char *file, int line)
+{
+ /* Roughly one percent of the calls to this function are to annotate
+ a node with the same information already attached to that node!
+ Just return instead of wasting memory. */
+ if (EXPR_LOCUS (node)
+ && (EXPR_FILENAME (node) == file
+ || ! strcmp (EXPR_FILENAME (node), file))
+ && EXPR_LINENO (node) == line)
{
- last_file = file;
- last_filenode = file ? get_identifier (file) : NULL_TREE;
+ last_annotated_node = node;
+ return;
}
- EXPR_WFL_FILENAME_NODE (wfl) = last_filenode;
- if (node)
+ /* In heavily macroized code (such as GCC itself) this single
+ entry cache can reduce the number of allocations by more
+ than half. */
+ if (last_annotated_node
+ && EXPR_LOCUS (last_annotated_node)
+ && (EXPR_FILENAME (last_annotated_node) == file
+ || ! strcmp (EXPR_FILENAME (last_annotated_node), file))
+ && EXPR_LINENO (last_annotated_node) == line)
{
- TREE_SIDE_EFFECTS (wfl) = TREE_SIDE_EFFECTS (node);
- TREE_TYPE (wfl) = TREE_TYPE (node);
+ SET_EXPR_LOCUS (node, EXPR_LOCUS (last_annotated_node));
+ return;
}
- return wfl;
+ SET_EXPR_LOCUS (node, ggc_alloc (sizeof (location_t)));
+ EXPR_LINENO (node) = line;
+ EXPR_FILENAME (node) = file;
+ last_annotated_node = node;
+}
+
+void
+annotate_with_locus (tree node, location_t locus)
+{
+ annotate_with_file_line (node, locus.file, locus.line);
}
\f
/* Return a declaration like DDECL except that its DECL_ATTRIBUTES
{
if (! attribute_list_equal (TYPE_ATTRIBUTES (ttype), attribute))
{
- unsigned int hashcode;
+ hashval_t hashcode = 0;
tree ntype;
+ enum tree_code code = TREE_CODE (ttype);
ntype = copy_node (ttype);
TYPE_NEXT_VARIANT (ntype) = 0;
set_type_quals (ntype, TYPE_UNQUALIFIED);
- hashcode = (TYPE_HASH (TREE_CODE (ntype))
- + TYPE_HASH (TREE_TYPE (ntype))
- + attribute_hash_list (attribute));
+ hashcode = iterative_hash_object (code, hashcode);
+ if (TREE_TYPE (ntype))
+ hashcode = iterative_hash_object (TYPE_HASH (TREE_TYPE (ntype)),
+ hashcode);
+ hashcode = attribute_hash_list (attribute, hashcode);
switch (TREE_CODE (ntype))
{
case FUNCTION_TYPE:
- hashcode += TYPE_HASH (TYPE_ARG_TYPES (ntype));
+ hashcode = type_hash_list (TYPE_ARG_TYPES (ntype), hashcode);
break;
case ARRAY_TYPE:
- hashcode += TYPE_HASH (TYPE_DOMAIN (ntype));
+ hashcode = iterative_hash_object (TYPE_HASH (TYPE_DOMAIN (ntype)),
+ hashcode);
break;
case INTEGER_TYPE:
- hashcode += TYPE_HASH (TYPE_MAX_VALUE (ntype));
+ hashcode = iterative_hash_object
+ (TREE_INT_CST_LOW (TYPE_MAX_VALUE (ntype)), hashcode);
+ hashcode = iterative_hash_object
+ (TREE_INT_CST_HIGH (TYPE_MAX_VALUE (ntype)), hashcode);
break;
case REAL_TYPE:
- hashcode += TYPE_HASH (TYPE_PRECISION (ntype));
+ {
+ unsigned int precision = TYPE_PRECISION (ntype);
+ hashcode = iterative_hash_object (precision, hashcode);
+ }
break;
default:
break;
TYPE_RESTRICT (type) = (type_quals & TYPE_QUAL_RESTRICT) != 0;
}
+/* Returns true iff cand is equivalent to base with type_quals. */
+
+bool
+check_qualified_type (tree cand, tree base, int type_quals)
+{
+ return (TYPE_QUALS (cand) == type_quals
+ && TYPE_NAME (cand) == TYPE_NAME (base)
+ /* Apparently this is needed for Objective-C. */
+ && TYPE_CONTEXT (cand) == TYPE_CONTEXT (base)
+ && attribute_list_equal (TYPE_ATTRIBUTES (cand),
+ TYPE_ATTRIBUTES (base)));
+}
+
/* Return a version of the TYPE, qualified as indicated by the
TYPE_QUALS, if one exists. If no qualified version exists yet,
return NULL_TREE. */
{
tree t;
+ if (TYPE_QUALS (type) == type_quals)
+ return type;
+
/* Search the chain of variants to see if there is already one there just
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)
- && TYPE_CONTEXT (t) == TYPE_CONTEXT (type))
+ if (check_qualified_type (t, type, type_quals))
return t;
return NULL_TREE;
of the individual types. */
unsigned int
-type_hash_list (tree list)
+type_hash_list (tree list, hashval_t hashcode)
{
- unsigned int hashcode;
tree tail;
- for (hashcode = 0, tail = list; tail; tail = TREE_CHAIN (tail))
- hashcode += TYPE_HASH (TREE_VALUE (tail));
+ for (tail = list; tail; tail = TREE_CHAIN (tail))
+ if (TREE_VALUE (tail) != error_mark_node)
+ hashcode = iterative_hash_object (TYPE_HASH (TREE_VALUE (tail)),
+ hashcode);
return hashcode;
}
/* These are the Hashtable callback functions. */
-/* Returns true if the types are equal. */
+/* Returns true iff the types are equivalent. */
static int
type_hash_eq (const void *va, const void *vb)
{
const struct type_hash *a = va, *b = vb;
- if (a->hash == b->hash
- && TREE_CODE (a->type) == TREE_CODE (b->type)
- && TREE_TYPE (a->type) == TREE_TYPE (b->type)
- && attribute_list_equal (TYPE_ATTRIBUTES (a->type),
- TYPE_ATTRIBUTES (b->type))
- && TYPE_ALIGN (a->type) == TYPE_ALIGN (b->type)
- && (TYPE_MAX_VALUE (a->type) == TYPE_MAX_VALUE (b->type)
- || tree_int_cst_equal (TYPE_MAX_VALUE (a->type),
- TYPE_MAX_VALUE (b->type)))
- && (TYPE_MIN_VALUE (a->type) == TYPE_MIN_VALUE (b->type)
- || tree_int_cst_equal (TYPE_MIN_VALUE (a->type),
- TYPE_MIN_VALUE (b->type)))
- /* Note that TYPE_DOMAIN is TYPE_ARG_TYPES for FUNCTION_TYPE. */
- && (TYPE_DOMAIN (a->type) == TYPE_DOMAIN (b->type)
- || (TYPE_DOMAIN (a->type)
- && TREE_CODE (TYPE_DOMAIN (a->type)) == TREE_LIST
- && TYPE_DOMAIN (b->type)
- && TREE_CODE (TYPE_DOMAIN (b->type)) == TREE_LIST
- && type_list_equal (TYPE_DOMAIN (a->type),
- TYPE_DOMAIN (b->type)))))
- return 1;
- return 0;
+
+ /* First test the things that are the same for all types. */
+ if (a->hash != b->hash
+ || TREE_CODE (a->type) != TREE_CODE (b->type)
+ || TREE_TYPE (a->type) != TREE_TYPE (b->type)
+ || !attribute_list_equal (TYPE_ATTRIBUTES (a->type),
+ TYPE_ATTRIBUTES (b->type))
+ || TYPE_ALIGN (a->type) != TYPE_ALIGN (b->type)
+ || TYPE_MODE (a->type) != TYPE_MODE (b->type))
+ return 0;
+
+ switch (TREE_CODE (a->type))
+ {
+ case VOID_TYPE:
+ case COMPLEX_TYPE:
+ case VECTOR_TYPE:
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ return 1;
+
+ case ENUMERAL_TYPE:
+ if (TYPE_VALUES (a->type) != TYPE_VALUES (b->type)
+ && !(TYPE_VALUES (a->type)
+ && TREE_CODE (TYPE_VALUES (a->type)) == TREE_LIST
+ && TYPE_VALUES (b->type)
+ && TREE_CODE (TYPE_VALUES (b->type)) == TREE_LIST
+ && type_list_equal (TYPE_VALUES (a->type),
+ TYPE_VALUES (b->type))))
+ return 0;
+
+ /* ... fall through ... */
+
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ case BOOLEAN_TYPE:
+ case CHAR_TYPE:
+ return ((TYPE_MAX_VALUE (a->type) == TYPE_MAX_VALUE (b->type)
+ || tree_int_cst_equal (TYPE_MAX_VALUE (a->type),
+ TYPE_MAX_VALUE (b->type)))
+ && (TYPE_MIN_VALUE (a->type) == TYPE_MIN_VALUE (b->type)
+ && tree_int_cst_equal (TYPE_MIN_VALUE (a->type),
+ TYPE_MIN_VALUE (b->type))));
+
+ case OFFSET_TYPE:
+ return TYPE_OFFSET_BASETYPE (a->type) == TYPE_OFFSET_BASETYPE (b->type);
+
+ case METHOD_TYPE:
+ return (TYPE_METHOD_BASETYPE (a->type) == TYPE_METHOD_BASETYPE (b->type)
+ && (TYPE_ARG_TYPES (a->type) == TYPE_ARG_TYPES (b->type)
+ || (TYPE_ARG_TYPES (a->type)
+ && TREE_CODE (TYPE_ARG_TYPES (a->type)) == TREE_LIST
+ && TYPE_ARG_TYPES (b->type)
+ && TREE_CODE (TYPE_ARG_TYPES (b->type)) == TREE_LIST
+ && type_list_equal (TYPE_ARG_TYPES (a->type),
+ TYPE_ARG_TYPES (b->type)))));
+
+ case ARRAY_TYPE:
+ case SET_TYPE:
+ return TYPE_DOMAIN (a->type) == TYPE_DOMAIN (b->type);
+
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ return (TYPE_FIELDS (a->type) == TYPE_FIELDS (b->type)
+ || (TYPE_FIELDS (a->type)
+ && TREE_CODE (TYPE_FIELDS (a->type)) == TREE_LIST
+ && TYPE_FIELDS (b->type)
+ && TREE_CODE (TYPE_FIELDS (b->type)) == TREE_LIST
+ && type_list_equal (TYPE_FIELDS (a->type),
+ TYPE_FIELDS (b->type))));
+
+ case FUNCTION_TYPE:
+ return (TYPE_ARG_TYPES (a->type) == TYPE_ARG_TYPES (b->type)
+ || (TYPE_ARG_TYPES (a->type)
+ && TREE_CODE (TYPE_ARG_TYPES (a->type)) == TREE_LIST
+ && TYPE_ARG_TYPES (b->type)
+ && TREE_CODE (TYPE_ARG_TYPES (b->type)) == TREE_LIST
+ && type_list_equal (TYPE_ARG_TYPES (a->type),
+ TYPE_ARG_TYPES (b->type))));
+
+ default:
+ return 0;
+ }
}
/* Return the cached hash value. */
If one is found, return it. Otherwise return 0. */
tree
-type_hash_lookup (unsigned int hashcode, tree type)
+type_hash_lookup (hashval_t hashcode, tree type)
{
struct type_hash *h, in;
for a type TYPE whose hash code is HASHCODE. */
void
-type_hash_add (unsigned int hashcode, tree type)
+type_hash_add (hashval_t 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);
/* Given TYPE, and HASHCODE its hash code, return the canonical
object for an identical type if one already exists.
- Otherwise, return TYPE, and record it as the canonical object
- if it is a permanent object.
+ Otherwise, return TYPE, and record it as the canonical object.
To use this function, first create a type of the sort you want.
Then compute its hash code from the fields of the type that
make it different from other similar types.
- Then call this function and use the value.
- This function frees the type you pass in if it is a duplicate. */
-
-/* Set to 1 to debug without canonicalization. Never set by program. */
-int debug_no_type_hash = 0;
+ Then call this function and use the value. */
tree
type_hash_canon (unsigned int hashcode, tree type)
{
tree t1;
- if (debug_no_type_hash)
+ /* The hash table only contains main variants, so ensure that's what we're
+ being passed. */
+ if (TYPE_MAIN_VARIANT (type) != type)
+ abort ();
+
+ if (!lang_hooks.types.hash_types)
return type;
/* See if the type is in the hash table already. If so, return it.
by adding the hash codes of the individual attributes. */
unsigned int
-attribute_hash_list (tree list)
+attribute_hash_list (tree list, hashval_t hashcode)
{
- unsigned int hashcode;
tree tail;
- for (hashcode = 0, tail = list; tail; tail = TREE_CHAIN (tail))
+ for (tail = list; tail; tail = TREE_CHAIN (tail))
/* ??? Do we want to add in TREE_VALUE too? */
- hashcode += TYPE_HASH (TREE_PURPOSE (tail));
+ hashcode = iterative_hash_object
+ (IDENTIFIER_HASH_VALUE (TREE_PURPOSE (tail)), hashcode);
return hashcode;
}
if (t1 == t2)
return 0;
- if (TREE_UNSIGNED (TREE_TYPE (t1)) != TREE_UNSIGNED (TREE_TYPE (t2)))
+ if (TYPE_UNSIGNED (TREE_TYPE (t1)) != TYPE_UNSIGNED (TREE_TYPE (t2)))
{
int t1_sgn = tree_int_cst_sgn (t1);
int t2_sgn = tree_int_cst_sgn (t2);
unsigned just in case one of them would overflow a signed
type. */
}
- else if (! TREE_UNSIGNED (TREE_TYPE (t1)))
+ else if (!TYPE_UNSIGNED (TREE_TYPE (t1)))
return INT_CST_LT (t1, t2);
return INT_CST_LT_UNSIGNED (t1, t2);
&& (HOST_WIDE_INT) TREE_INT_CST_LOW (t) >= 0)
|| (! pos && TREE_INT_CST_HIGH (t) == -1
&& (HOST_WIDE_INT) TREE_INT_CST_LOW (t) < 0
- && ! TREE_UNSIGNED (TREE_TYPE (t)))
+ && !TYPE_UNSIGNED (TREE_TYPE (t)))
|| (pos && TREE_INT_CST_HIGH (t) == 0)));
}
{
if (TREE_INT_CST_LOW (t) == 0 && TREE_INT_CST_HIGH (t) == 0)
return 0;
- else if (TREE_UNSIGNED (TREE_TYPE (t)))
+ else if (TYPE_UNSIGNED (TREE_TYPE (t)))
return 1;
else if (TREE_INT_CST_HIGH (t) < 0)
return -1;
TREE_STRING_LENGTH (t1)));
case CONSTRUCTOR:
- if (CONSTRUCTOR_ELTS (t1) == CONSTRUCTOR_ELTS (t2))
- return 1;
- else
- abort ();
+ return simple_cst_list_equal (CONSTRUCTOR_ELTS (t1),
+ CONSTRUCTOR_ELTS (t2));
case SAVE_EXPR:
return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
return 1;
}
+/* Return true if CODE represents an associative tree code. Otherwise
+ return false. */
+bool
+associative_tree_code (enum tree_code code)
+{
+ switch (code)
+ {
+ case BIT_IOR_EXPR:
+ case BIT_AND_EXPR:
+ case BIT_XOR_EXPR:
+ case PLUS_EXPR:
+ case MULT_EXPR:
+ case MIN_EXPR:
+ case MAX_EXPR:
+ return true;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+/* Return true if CODE represents an commutative tree code. Otherwise
+ return false. */
+bool
+commutative_tree_code (enum tree_code code)
+{
+ switch (code)
+ {
+ case PLUS_EXPR:
+ case MULT_EXPR:
+ case MIN_EXPR:
+ case MAX_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ case BIT_AND_EXPR:
+ case NE_EXPR:
+ case EQ_EXPR:
+ return true;
+
+ default:
+ break;
+ }
+ return false;
+}
+
/* Generate a hash value for an expression. This can be used iteratively
by passing a previous result as the "val" argument.
else
abort ();
}
- else if (IS_EXPR_CODE_CLASS (class) || class == 'r')
+ else if (IS_EXPR_CODE_CLASS (class))
{
val = iterative_hash_object (code, val);
- if (code == NOP_EXPR || code == CONVERT_EXPR
+ /* Don't hash the type, that can lead to having nodes which
+ compare equal according to operand_equal_p, but which
+ have different hash codes. */
+ if (code == NOP_EXPR
+ || code == CONVERT_EXPR
|| code == NON_LVALUE_EXPR)
- val = iterative_hash_object (TREE_TYPE (t), val);
+ {
+ /* Make sure to include signness in the hash computation. */
+ val += TYPE_UNSIGNED (TREE_TYPE (t));
+ val = iterative_hash_expr (TREE_OPERAND (t, 0), 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)
+ if (commutative_tree_code (code))
{
/* It's a commutative expression. We want to hash it the same
however it appears. We do this by first hashing both operands
for (; t; t = TREE_CHAIN (t))
val = iterative_hash_expr (TREE_VALUE (t), val);
}
+ else if (code == SSA_NAME)
+ {
+ val = iterative_hash_object (SSA_NAME_VERSION (t), val);
+ val = iterative_hash_expr (SSA_NAME_VAR (t), val);
+ }
else
abort ();
(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
- with mode MODE. 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 CAN_ALIAS_ALL is TRUE, indicate this type can
+ reference all of memory. If such a type has already been
+ constructed, reuse it. */
tree
-build_pointer_type_for_mode (tree to_type, enum machine_mode mode)
+build_pointer_type_for_mode (tree to_type, enum machine_mode mode,
+ bool can_alias_all)
{
- tree t = TYPE_POINTER_TO (to_type);
+ tree t;
- /* First, if we already have a type for pointers to TO_TYPE, use it. */
- if (t != 0 && mode == ptr_mode)
- return t;
+ /* In some cases, languages will have things that aren't a POINTER_TYPE
+ (such as a RECORD_TYPE for fat pointers in Ada) as TYPE_POINTER_TO.
+ In that case, return that type without regard to the rest of our
+ operands.
+
+ ??? This is a kludge, but consistent with the way this function has
+ always operated and there doesn't seem to be a good way to avoid this
+ at the moment. */
+ if (TYPE_POINTER_TO (to_type) != 0
+ && TREE_CODE (TYPE_POINTER_TO (to_type)) != POINTER_TYPE)
+ return TYPE_POINTER_TO (to_type);
+
+ /* First, if we already have a type for pointers to TO_TYPE and it's
+ the proper mode, use it. */
+ for (t = TYPE_POINTER_TO (to_type); t; t = TYPE_NEXT_PTR_TO (t))
+ if (TYPE_MODE (t) == mode && TYPE_REF_CAN_ALIAS_ALL (t) == can_alias_all)
+ return t;
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_REF_CAN_ALIAS_ALL (t) = can_alias_all;
+ TYPE_NEXT_PTR_TO (t) = TYPE_POINTER_TO (to_type);
TYPE_POINTER_TO (to_type) = t;
/* Lay out the type. This function has many callers that are concerned
- with expression-construction, and this simplifies them all.
- Also, it guarantees the TYPE_SIZE is in the same obstack as the type. */
+ with expression-construction, and this simplifies them all. */
layout_type (t);
return t;
tree
build_pointer_type (tree to_type)
{
- return build_pointer_type_for_mode (to_type, ptr_mode);
+ return build_pointer_type_for_mode (to_type, ptr_mode, false);
}
-/* 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. */
+/* Same as build_pointer_type_for_mode, but for REFERENCE_TYPE. */
tree
-build_reference_type_for_mode (tree to_type, enum machine_mode mode)
+build_reference_type_for_mode (tree to_type, enum machine_mode mode,
+ bool can_alias_all)
{
- tree t = TYPE_REFERENCE_TO (to_type);
+ tree t;
- /* First, if we already have a type for pointers to TO_TYPE, use it. */
- if (t != 0 && mode == ptr_mode)
- return t;
+ /* In some cases, languages will have things that aren't a REFERENCE_TYPE
+ (such as a RECORD_TYPE for fat pointers in Ada) as TYPE_REFERENCE_TO.
+ In that case, return that type without regard to the rest of our
+ operands.
+
+ ??? This is a kludge, but consistent with the way this function has
+ always operated and there doesn't seem to be a good way to avoid this
+ at the moment. */
+ if (TYPE_REFERENCE_TO (to_type) != 0
+ && TREE_CODE (TYPE_REFERENCE_TO (to_type)) != REFERENCE_TYPE)
+ return TYPE_REFERENCE_TO (to_type);
+
+ /* First, if we already have a type for pointers to TO_TYPE and it's
+ the proper mode, use it. */
+ for (t = TYPE_REFERENCE_TO (to_type); t; t = TYPE_NEXT_REF_TO (t))
+ if (TYPE_MODE (t) == mode && TYPE_REF_CAN_ALIAS_ALL (t) == can_alias_all)
+ return t;
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_REF_CAN_ALIAS_ALL (t) = can_alias_all;
+ TYPE_NEXT_REF_TO (t) = TYPE_REFERENCE_TO (to_type);
TYPE_REFERENCE_TO (to_type) = t;
layout_type (t);
tree
build_reference_type (tree to_type)
{
- return build_reference_type_for_mode (to_type, ptr_mode);
+ return build_reference_type_for_mode (to_type, ptr_mode, false);
}
/* Build a type that is compatible with t but has no cv quals anywhere
switch (TREE_CODE (t))
{
case POINTER_TYPE:
- return build_pointer_type (build_type_no_quals (TREE_TYPE (t)));
+ return build_pointer_type_for_mode (build_type_no_quals (TREE_TYPE (t)),
+ TYPE_MODE (t),
+ TYPE_REF_CAN_ALIAS_ALL (t));
case REFERENCE_TYPE:
- return build_reference_type (build_type_no_quals (TREE_TYPE (t)));
+ return
+ build_reference_type_for_mode (build_type_no_quals (TREE_TYPE (t)),
+ TYPE_MODE (t),
+ TYPE_REF_CAN_ALIAS_ALL (t));
default:
return TYPE_MAIN_VARIANT (t);
}
build_array_type (tree elt_type, tree index_type)
{
tree t;
- unsigned int hashcode;
+ hashval_t hashcode = 0;
if (TREE_CODE (elt_type) == FUNCTION_TYPE)
{
elt_type = integer_type_node;
}
- /* Make sure TYPE_POINTER_TO (elt_type) is filled in. */
- build_pointer_type (elt_type);
-
- /* Allocate the array after the pointer type,
- in case we free it in type_hash_canon. */
t = make_node (ARRAY_TYPE);
TREE_TYPE (t) = elt_type;
TYPE_DOMAIN (t) = index_type;
if (index_type == 0)
- {
- return t;
- }
+ return t;
- hashcode = TYPE_HASH (elt_type) + TYPE_HASH (index_type);
+ hashcode = iterative_hash_object (TYPE_HASH (elt_type), hashcode);
+ hashcode = iterative_hash_object (TYPE_HASH (index_type), hashcode);
t = type_hash_canon (hashcode, t);
if (!COMPLETE_TYPE_P (t))
build_function_type (tree value_type, tree arg_types)
{
tree t;
- unsigned int hashcode;
+ hashval_t hashcode = 0;
if (TREE_CODE (value_type) == FUNCTION_TYPE)
{
TREE_TYPE (t) = value_type;
TYPE_ARG_TYPES (t) = arg_types;
- /* If we already have such a type, use the old one and free this one. */
- hashcode = TYPE_HASH (value_type) + type_hash_list (arg_types);
+ /* If we already have such a type, use the old one. */
+ hashcode = iterative_hash_object (TYPE_HASH (value_type), hashcode);
+ hashcode = type_hash_list (arg_types, hashcode);
t = type_hash_canon (hashcode, t);
if (!COMPLETE_TYPE_P (t))
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. */
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 (tree basetype, tree type)
+build_method_type_directly (tree basetype,
+ tree rettype,
+ tree argtypes)
{
tree t;
- unsigned int hashcode;
+ tree ptype;
+ int hashcode = 0;
/* 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. */
- hashcode = TYPE_HASH (basetype) + TYPE_HASH (type);
+ /* If we already have such a type, use the old one. */
+ hashcode = iterative_hash_object (TYPE_HASH (basetype), hashcode);
+ hashcode = iterative_hash_object (TYPE_HASH (rettype), hashcode);
+ hashcode = type_hash_list (argtypes, hashcode);
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. */
build_offset_type (tree basetype, tree type)
{
tree t;
- unsigned int hashcode;
+ hashval_t hashcode = 0;
/* Make a node of the sort we want. */
t = make_node (OFFSET_TYPE);
TYPE_OFFSET_BASETYPE (t) = TYPE_MAIN_VARIANT (basetype);
TREE_TYPE (t) = type;
- /* If we already have such a type, use the old one and free this one. */
- hashcode = TYPE_HASH (basetype) + TYPE_HASH (type);
+ /* If we already have such a type, use the old one. */
+ hashcode = iterative_hash_object (TYPE_HASH (basetype), hashcode);
+ hashcode = iterative_hash_object (TYPE_HASH (type), hashcode);
t = type_hash_canon (hashcode, t);
if (!COMPLETE_TYPE_P (t))
build_complex_type (tree component_type)
{
tree t;
- unsigned int hashcode;
+ hashval_t hashcode;
/* Make a node of the sort we want. */
t = make_node (COMPLEX_TYPE);
TREE_TYPE (t) = TYPE_MAIN_VARIANT (component_type);
- set_type_quals (t, TYPE_QUALS (component_type));
- /* If we already have such a type, use the old one and free this one. */
- hashcode = TYPE_HASH (component_type);
+ /* If we already have such a type, use the old one. */
+ hashcode = iterative_hash_object (TYPE_HASH (component_type), 0);
t = type_hash_canon (hashcode, t);
if (!COMPLETE_TYPE_P (t))
TYPE_NAME (t) = get_identifier (name);
}
- return t;
+ return build_qualified_type (t, TYPE_QUALS (component_type));
}
\f
/* Return OP, stripped of any conversions to wider types as much as is safe.
int uns
= (for_type != 0 && for_type != type
&& final_prec > TYPE_PRECISION (type)
- && TREE_UNSIGNED (type));
+ && TYPE_UNSIGNED (type));
tree win = op;
while (TREE_CODE (op) == NOP_EXPR)
{
if (! uns || final_prec <= TYPE_PRECISION (TREE_TYPE (op)))
win = op;
- /* TREE_UNSIGNED says whether this is a zero-extension.
+ /* TYPE_UNSIGNED says whether this is a zero-extension.
Let's avoid computing it if it does not affect WIN
and if UNS will not be needed again. */
if ((uns || TREE_CODE (op) == NOP_EXPR)
- && TREE_UNSIGNED (TREE_TYPE (op)))
+ && TYPE_UNSIGNED (TREE_TYPE (op)))
{
uns = 1;
win = op;
{
unsigned int innerprec
= tree_low_cst (DECL_SIZE (TREE_OPERAND (op, 1)), 1);
- int unsignedp = TREE_UNSIGNED (TREE_OPERAND (op, 1));
- type = (*lang_hooks.types.type_for_size) (innerprec, unsignedp);
+ int unsignedp = (DECL_UNSIGNED (TREE_OPERAND (op, 1))
+ || TYPE_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.
If FOR_TYPE is 0, do this only for a field that matches the
The resulting extension to its nominal type (a fullword type)
must fit the same conditions as for other extensions. */
- if (innerprec < TYPE_PRECISION (TREE_TYPE (op))
+ if (type != 0
+ && INT_CST_LT_UNSIGNED (TYPE_SIZE (type), TYPE_SIZE (TREE_TYPE (op)))
&& (for_type || ! DECL_BIT_FIELD (TREE_OPERAND (op, 1)))
- && (! uns || final_prec <= innerprec || unsignedp)
- && type != 0)
+ && (! uns || final_prec <= innerprec || unsignedp))
{
win = build (COMPONENT_REF, type, TREE_OPERAND (op, 0),
TREE_OPERAND (op, 1));
/* An extension: the outermost one can be stripped,
but remember whether it is zero or sign extension. */
if (first)
- uns = TREE_UNSIGNED (TREE_TYPE (op));
+ uns = TYPE_UNSIGNED (TREE_TYPE (op));
/* Otherwise, if a sign extension has been stripped,
only sign extensions can now be stripped;
if a zero extension has been stripped, only zero-extensions. */
- else if (uns != TREE_UNSIGNED (TREE_TYPE (op)))
+ else if (uns != TYPE_UNSIGNED (TREE_TYPE (op)))
break;
first = 0;
}
/* A change in nominal type can always be stripped, but we must
preserve the unsignedness. */
if (first)
- uns = TREE_UNSIGNED (TREE_TYPE (op));
+ uns = TYPE_UNSIGNED (TREE_TYPE (op));
first = 0;
op = TREE_OPERAND (op, 0);
}
{
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 = (DECL_UNSIGNED (TREE_OPERAND (op, 1))
+ || TYPE_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)
if (innerprec < TYPE_PRECISION (TREE_TYPE (op))
&& ! DECL_BIT_FIELD (TREE_OPERAND (op, 1))
- && (first || uns == TREE_UNSIGNED (TREE_OPERAND (op, 1)))
+ && (first || uns == DECL_UNSIGNED (TREE_OPERAND (op, 1)))
&& type != 0)
{
if (first)
- uns = TREE_UNSIGNED (TREE_OPERAND (op, 1));
+ uns = DECL_UNSIGNED (TREE_OPERAND (op, 1));
win = build (COMPONENT_REF, type, TREE_OPERAND (op, 0),
TREE_OPERAND (op, 1));
TREE_SIDE_EFFECTS (win) = TREE_SIDE_EFFECTS (op);
/* 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)
+ if ((TYPE_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)))
+ || (! TYPE_UNSIGNED (type)
+ && TYPE_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
bool
variably_modified_type_p (tree type)
{
+ tree t;
+
if (type == error_mark_node)
return false;
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)))
+ t = TYPE_SIZE (type);
+ if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST)
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:
+ case SET_TYPE:
+ case VECTOR_TYPE:
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)))
+ break;
+
+ 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. */
+ if (variably_modified_type_p (TREE_TYPE (type)))
+ return true;
+
+ for (t = TYPE_ARG_TYPES (type);
+ t && t != void_list_node;
+ t = TREE_CHAIN (t))
+ if (variably_modified_type_p (TREE_VALUE (t)))
return true;
+ break;
+
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ case ENUMERAL_TYPE:
+ case BOOLEAN_TYPE:
+ case CHAR_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;
+ break;
+
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ /* We can't see if any of the field are variably-modified by the
+ definition we normally use, since that would produce infinite
+ recursion via pointers. */
+ /* This is variably modified if some field's type is. */
+ for (t = TYPE_FIELDS (type); t; t = TREE_CHAIN (t))
+ if (TREE_CODE (t) == FIELD_DECL)
+ {
+ tree t1 = DECL_FIELD_OFFSET (t);
+
+ if (t1 && t1 != error_mark_node && TREE_CODE (t1) != INTEGER_CST)
+ return true;
+
+ t1 = DECL_SIZE (t);
+ if (t1 && t1 != error_mark_node && TREE_CODE (t1) != INTEGER_CST)
+ return true;
+ }
+ break;
+
+ default:
+ break;
}
/* 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);
+ return lang_hooks.tree_inlining.var_mod_type_p (type);
}
/* Given a DECL or TYPE, return the scope in which it was declared, or
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;
}
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,
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");
+ ssanames_print_statistics ();
+ phinodes_print_statistics ();
#else
fprintf (stderr, "(No per-node statistics)\n");
#endif
print_type_hash_statistics ();
- (*lang_hooks.print_statistics) ();
+ lang_hooks.print_statistics ();
}
\f
#define FILE_FUNCTION_FORMAT "_GLOBAL__%s_%s"
-const char *flag_random_seed;
-
-/* Set up a default flag_random_seed value, if there wasn't one already. */
-
-void
-default_flag_random_seed (void)
-{
- unsigned HOST_WIDE_INT value;
- char *new_random_seed;
-
- if (flag_random_seed != NULL)
- return;
-
- /* Get some more or less random data. */
-#ifdef HAVE_GETTIMEOFDAY
- {
- struct timeval tv;
-
- gettimeofday (&tv, NULL);
- value = (((unsigned HOST_WIDE_INT) tv.tv_usec << 16)
- ^ tv.tv_sec ^ getpid ());
- }
-#else
- value = getpid ();
-#endif
-
- /* This slightly overestimates the space required. */
- new_random_seed = xmalloc (HOST_BITS_PER_WIDE_INT / 3 + 2);
- sprintf (new_random_seed, HOST_WIDE_INT_PRINT_UNSIGNED, value);
- flag_random_seed = new_random_seed;
-}
-
/* Generate a crc32 of a string. */
unsigned
file = input_filename;
len = strlen (file);
- q = (char *) alloca (9 * 2 + len);
+ q = alloca (9 * 2 + len + 1);
memcpy (q, file, len + 1);
clean_symbol_name (q);
- default_flag_random_seed ();
sprintf (q + len, "_%08X_%08X", crc32_string (0, name),
crc32_string (0, flag_random_seed));
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
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++)
}
\f
#if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007)
+
/* Complain that the tree code of NODE does not match the expected CODE.
FILE, LINE, and FUNCTION are of the caller. */
function, trim_filename (file), line);
}
-/* Similar to above, except that we check for a class of tree
+/* Similar to above except that we allowed the code to be one of two
+ different codes. */
+
+void
+tree_check2_failed (const tree node, enum tree_code code1,
+ enum tree_code code2, const char *file,
+ int line, const char *function)
+{
+ internal_error ("tree check: expected %s or %s, have %s in %s, at %s:%d",
+ tree_code_name[code1], tree_code_name[code2],
+ tree_code_name[TREE_CODE (node)],
+ function, trim_filename (file), line);
+}
+
+/* Likewise for three different codes. */
+
+void
+tree_check3_failed (const tree node, enum tree_code code1,
+ enum tree_code code2, enum tree_code code3,
+ const char *file, int line, const char *function)
+{
+ internal_error ("tree check: expected %s, %s or %s; have %s in %s, at %s:%d",
+ tree_code_name[code1], tree_code_name[code2],
+ tree_code_name[code3], tree_code_name[TREE_CODE (node)],
+ function, trim_filename (file), line);
+}
+
+/* ... and for four different codes. */
+
+void
+tree_check4_failed (const tree node, enum tree_code code1,
+ enum tree_code code2, enum tree_code code3,
+ enum tree_code code4, const char *file, int line,
+ const char *function)
+{
+ internal_error
+ ("tree check: expected %s, %s, %s or %s; have %s in %s, at %s:%d",
+ tree_code_name[code1], tree_code_name[code2], tree_code_name[code3],
+ tree_code_name[code4], tree_code_name[TREE_CODE (node)], function,
+ trim_filename (file), line);
+}
+
+/* ... and for five different codes. */
+
+void
+tree_check5_failed (const tree node, enum tree_code code1,
+ enum tree_code code2, enum tree_code code3,
+ enum tree_code code4, enum tree_code code5,
+ const char *file, int line, const char *function)
+{
+ internal_error
+ ("tree check: expected %s, %s, %s, %s or %s; have %s in %s, at %s:%d",
+ tree_code_name[code1], tree_code_name[code2], tree_code_name[code3],
+ tree_code_name[code4], tree_code_name[code5],
+ tree_code_name[TREE_CODE (node)], function, trim_filename (file), line);
+}
+
+/* Similar to tree_check_failed, except that we check for a class of tree
code, given in CL. */
void
idx + 1, len, function, trim_filename (file), line);
}
+/* Similar to above, except that the check is for the bounds of a EPHI_NODE's
+ (dynamically sized) vector. */
+
+void
+ephi_node_elt_check_failed (int idx, int len, const char *file, int line,
+ const char *function)
+{
+ internal_error
+ ("tree check: accessed elt %d of ephi_node 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 a PHI_NODE's
+ (dynamically sized) vector. */
+
+void
+phi_node_elt_check_failed (int idx, int len, const char *file, int line,
+ const char *function)
+{
+ internal_error
+ ("tree check: accessed elt %d of phi_node 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. */
}
}
+static tree
+make_or_reuse_type (unsigned size, int unsignedp)
+{
+ if (size == INT_TYPE_SIZE)
+ return unsignedp ? unsigned_type_node : integer_type_node;
+ if (size == CHAR_TYPE_SIZE)
+ return unsignedp ? unsigned_char_type_node : signed_char_type_node;
+ if (size == SHORT_TYPE_SIZE)
+ return unsignedp ? short_unsigned_type_node : short_integer_type_node;
+ if (size == LONG_TYPE_SIZE)
+ return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+ if (size == LONG_LONG_TYPE_SIZE)
+ return (unsignedp ? long_long_unsigned_type_node
+ : long_long_integer_type_node);
+
+ if (unsignedp)
+ return make_unsigned_type (size);
+ else
+ return make_signed_type (size);
+}
+
/* Create nodes for all integer types (and error_mark_node) using the sizes
of C datatypes. The caller should call set_sizetype soon after calling
this function to select one of the types as sizetype. */
long_long_integer_type_node = make_signed_type (LONG_LONG_TYPE_SIZE);
long_long_unsigned_type_node = make_unsigned_type (LONG_LONG_TYPE_SIZE);
- intQI_type_node = make_signed_type (GET_MODE_BITSIZE (QImode));
- intHI_type_node = make_signed_type (GET_MODE_BITSIZE (HImode));
- intSI_type_node = make_signed_type (GET_MODE_BITSIZE (SImode));
- intDI_type_node = make_signed_type (GET_MODE_BITSIZE (DImode));
- intTI_type_node = make_signed_type (GET_MODE_BITSIZE (TImode));
-
- unsigned_intQI_type_node = make_unsigned_type (GET_MODE_BITSIZE (QImode));
- unsigned_intHI_type_node = make_unsigned_type (GET_MODE_BITSIZE (HImode));
- unsigned_intSI_type_node = make_unsigned_type (GET_MODE_BITSIZE (SImode));
- unsigned_intDI_type_node = make_unsigned_type (GET_MODE_BITSIZE (DImode));
- unsigned_intTI_type_node = make_unsigned_type (GET_MODE_BITSIZE (TImode));
+ /* 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;
+
+ /* Fill in the rest of the sized types. Reuse existing type nodes
+ when possible. */
+ intQI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (QImode), 0);
+ intHI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (HImode), 0);
+ intSI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (SImode), 0);
+ intDI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (DImode), 0);
+ intTI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (TImode), 0);
+
+ unsigned_intQI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (QImode), 1);
+ unsigned_intHI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (HImode), 1);
+ unsigned_intSI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (SImode), 1);
+ unsigned_intDI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (DImode), 1);
+ unsigned_intTI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (TImode), 1);
+
+ access_public_node = get_identifier ("public");
+ access_protected_node = get_identifier ("protected");
+ access_private_node = get_identifier ("private");
}
/* Call this function after calling build_common_tree_nodes and set_sizetype.
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 setting TYPE_NAME.
If we copied the record type here, we'd keep the original
va_list_type_node = 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 (V8QImode, unsigned_intQI_type_node, 1);
- unsigned_V8HI_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
- the signness. */
+/* HACK. GROSS. This is absolutely disgusting. I wish there was a
+ better way.
-static tree
-make_vector (enum machine_mode mode, tree innertype, int unsignedp)
+ If we requested a pointer to a vector, build up the pointers that
+ we stripped off while looking for the inner type. Similarly for
+ return values from functions.
+
+ The argument TYPE is the top of the chain, and BOTTOM is the
+ new type which we will point to. */
+
+tree
+reconstruct_complex_type (tree type, tree bottom)
{
- tree t;
+ tree inner, outer;
+
+ if (POINTER_TYPE_P (type))
+ {
+ inner = reconstruct_complex_type (TREE_TYPE (type), bottom);
+ outer = build_pointer_type (inner);
+ }
+ else if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ inner = reconstruct_complex_type (TREE_TYPE (type), bottom);
+ outer = build_array_type (inner, TYPE_DOMAIN (type));
+ }
+ else if (TREE_CODE (type) == FUNCTION_TYPE)
+ {
+ inner = reconstruct_complex_type (TREE_TYPE (type), bottom);
+ outer = build_function_type (inner, TYPE_ARG_TYPES (type));
+ }
+ else if (TREE_CODE (type) == METHOD_TYPE)
+ {
+ inner = reconstruct_complex_type (TREE_TYPE (type), bottom);
+ outer = build_method_type_directly (TYPE_METHOD_BASETYPE (type),
+ inner,
+ TYPE_ARG_TYPES (type));
+ }
+ else
+ return bottom;
+
+ TYPE_READONLY (outer) = TYPE_READONLY (type);
+ TYPE_VOLATILE (outer) = TYPE_VOLATILE (type);
+
+ return outer;
+}
+/* Returns a vector tree node given a vector mode and inner type. */
+tree
+build_vector_type_for_mode (tree innertype, enum machine_mode mode)
+{
+ tree t;
t = make_node (VECTOR_TYPE);
TREE_TYPE (t) = innertype;
TYPE_MODE (t) = mode;
- TREE_UNSIGNED (TREE_TYPE (t)) = unsignedp;
finish_vector_type (t);
-
return t;
}
+/* Similarly, but takes inner type and units. */
+
+tree
+build_vector_type (tree innertype, int nunits)
+{
+ enum machine_mode innermode = TYPE_MODE (innertype);
+ enum machine_mode mode;
+
+ if (GET_MODE_CLASS (innermode) == MODE_FLOAT)
+ mode = MIN_MODE_VECTOR_FLOAT;
+ else
+ mode = MIN_MODE_VECTOR_INT;
+
+ for (; mode != VOIDmode ; mode = GET_MODE_WIDER_MODE (mode))
+ if (GET_MODE_NUNITS (mode) == nunits && GET_MODE_INNER (mode) == innermode)
+ return build_vector_type_for_mode (innertype, mode);
+
+ return NULL_TREE;
+}
+
/* Given an initializer INIT, return TRUE if INIT is zero or some
aggregate of zeros. Otherwise return FALSE. */
-
bool
initializer_zerop (tree init)
{
+ tree elt;
+
STRIP_NOPS (init);
switch (TREE_CODE (init))
{
case INTEGER_CST:
return integer_zerop (init);
+
case REAL_CST:
+ /* ??? Note that this is not correct for C4X float formats. There,
+ a bit pattern of all zeros is 1.0; 0.0 is encoded with the most
+ negative exponent. */
return real_zerop (init)
&& ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (init));
+
case COMPLEX_CST:
return integer_zerop (init)
|| (real_zerop (init)
&& ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_REALPART (init)))
&& ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_IMAGPART (init))));
+
+ case VECTOR_CST:
+ for (elt = TREE_VECTOR_CST_ELTS (init); elt; elt = TREE_CHAIN (elt))
+ if (!initializer_zerop (TREE_VALUE (elt)))
+ return false;
+ return true;
+
case CONSTRUCTOR:
- {
- if (AGGREGATE_TYPE_P (TREE_TYPE (init)))
- {
- 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;
- }
+ elt = CONSTRUCTOR_ELTS (init);
+ if (elt == NULL_TREE)
+ return true;
+
+ /* A set is empty only if it has no elements. */
+ if (TREE_CODE (TREE_TYPE (init)) == SET_TYPE)
return false;
- }
+
+ for (; elt ; elt = TREE_CHAIN (elt))
+ if (! initializer_zerop (TREE_VALUE (elt)))
+ return false;
+ return true;
+
default:
return false;
}
}
+void
+add_var_to_bind_expr (tree bind_expr, tree var)
+{
+ BIND_EXPR_VARS (bind_expr)
+ = chainon (BIND_EXPR_VARS (bind_expr), var);
+ if (BIND_EXPR_BLOCK (bind_expr))
+ BLOCK_VARS (BIND_EXPR_BLOCK (bind_expr))
+ = BIND_EXPR_VARS (bind_expr);
+}
+
+/* Build an empty statement. */
+
+tree
+build_empty_stmt (void)
+{
+ return build1 (NOP_EXPR, void_type_node, size_zero_node);
+}
+
+bool
+is_essa_node (tree t)
+{
+ if (TREE_CODE (t) == EPHI_NODE || TREE_CODE (t) == EUSE_NODE
+ || TREE_CODE (t) == EEXIT_NODE || TREE_CODE (t) == EKILL_NODE)
+ return true;
+ return false;
+}
+
+
+/* Return true if T (assumed to be a DECL) must be assigned a memory
+ location. */
+
+bool
+needs_to_live_in_memory (tree t)
+{
+ return (DECL_NEEDS_TO_LIVE_IN_MEMORY_INTERNAL (t)
+ || TREE_STATIC (t)
+ || DECL_EXTERNAL (t)
+ || DECL_NONLOCAL (t)
+ || (TREE_CODE (t) == RESULT_DECL
+ && aggregate_value_p (t, current_function_decl))
+ || decl_function_context (t) != current_function_decl);
+}
+
#include "gt-tree.h"