#include "output.h"
#include "target.h"
#include "langhooks.h"
+#include "tree-iterator.h"
+#include "basic-block.h"
+#include "tree-flow.h"
+#include "opts.h"
/* obstack.[ch] explicitly declined to prototype this. */
extern int _obstack_allocated_p (struct obstack *h, void *obj);
"perm_tree_lists",
"temp_tree_lists",
"vecs",
+ "binfos",
+ "phi_nodes",
+ "ssa names",
"random kinds",
"lang_decl kinds",
"lang_type kinds"
tree type;
};
+/* Additional language-dependent binfo slots. */
+unsigned binfo_lang_slots;
+
/* Initial size of the hash table (rounded to next prime). */
#define TYPE_HASH_INITIAL_SIZE 1000
static void print_type_hash_statistics (void);
static void finish_vector_type (tree);
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 't': /* a type node */
return sizeof (struct tree_type);
- case 'b': /* a lexical block node */
- return sizeof (struct tree_block);
-
case 'r': /* a reference */
case 'e': /* an expression */
case 's': /* an expression with side effects */
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 SSA_NAME: return sizeof (struct tree_ssa_name);
+
+ case STATEMENT_LIST: return sizeof (struct tree_statement_list);
+ case BLOCK: return sizeof (struct tree_block);
+ case VALUE_HANDLE: return sizeof (struct tree_value_handle);
+
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, or STRING_CST
+ without knowing how many elements it will have. */
+ if (code == TREE_VEC || code == PHI_NODE)
abort ();
TREE_SET_CODE ((tree)&ttmp, code);
kind = t_kind;
break;
- case 'b': /* a lexical block */
- kind = b_kind;
- break;
-
case 's': /* an expression with side effects */
kind = s_kind;
break;
kind = id_kind;
else if (code == TREE_VEC)
kind = vec_kind;
+ else if (code == TREE_BINFO)
+ kind = binfo_kind;
+ else if (code == PHI_NODE)
+ kind = phi_kind;
+ else if (code == SSA_NAME)
+ kind = ssa_name_kind;
+ else if (code == BLOCK)
+ kind = b_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);
DECL_USER_ALIGN (t) = 0;
DECL_IN_SYSTEM_HEADER (t) = in_system_header;
DECL_SOURCE_LOCATION (t) = input_location;
- DECL_UID (t) = next_decl_uid++;
+ if (code == TRANSLATION_UNIT_DECL)
+ DECL_UID (t) = cur_in_fname;
+ else
+ DECL_UID (t) = next_decl_uid++;
/* We have not yet computed the alias set for this declaration. */
DECL_POINTER_ALIAS_SET (t) = -1;
/* 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':
case INIT_EXPR:
case MODIFY_EXPR:
case VA_ARG_EXPR:
- case RTL_EXPR:
case PREDECREMENT_EXPR:
case PREINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
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')
+ if (TREE_CODE_CLASS (code) == 'd' && code != TRANSLATION_UNIT_DECL)
DECL_UID (t) = next_decl_uid++;
else if (TREE_CODE_CLASS (code) == 't')
{
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;
}
real_from_integer (&d, type ? TYPE_MODE (type) : VOIDmode,
TREE_INT_CST_LOW (i), TREE_INT_CST_HIGH (i),
- TREE_UNSIGNED (TREE_TYPE (i)));
+ TYPE_UNSIGNED (TREE_TYPE (i)));
return d;
}
return t;
}
+/* Build a BINFO with LEN language slots. */
+
+tree
+make_tree_binfo_stat (unsigned lang_slots MEM_STAT_DECL)
+{
+ tree t;
+ static unsigned length;
+
+ if (!length)
+ {
+ length = (offsetof (struct tree_binfo, lang_slots)
+ + (sizeof (((struct tree_binfo *)0)->lang_slots[0])
+ * lang_slots));
+ binfo_lang_slots = lang_slots;
+ }
+ else if (binfo_lang_slots != lang_slots)
+ abort ();
+
+#ifdef GATHER_STATISTICS
+ tree_node_counts[(int) binfo_kind]++;
+ tree_node_sizes[(int) binfo_kind] += length;
+#endif
+
+ t = ggc_alloc_zone_stat (length, tree_zone PASS_MEM_STAT);
+
+ memset (t, 0, length);
+
+ TREE_SET_CODE (t, TREE_BINFO);
+
+ return t;
+}
+
+
/* 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));
return (integer_zerop (min)
? max
- : fold (build (MINUS_EXPR, TREE_TYPE (max), max, min)));
+ : fold (build2 (MINUS_EXPR, TREE_TYPE (max), max, min)));
}
\f
/* Return nonzero if arg is static -- a reference to an object in
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)
if (contains_placeholder_p (inner))
return t;
- t = build (SAVE_EXPR, TREE_TYPE (expr), t, current_function_decl, NULL_TREE);
+ t = build1 (SAVE_EXPR, TREE_TYPE (expr), t);
/* This expression might be placed ahead of a jump to ensure that the
value was computed on both sides of the jump. So make sure it isn't
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 inner;
}
-/* Return TRUE if EXPR is a SAVE_EXPR or wraps simple arithmetic around a
- SAVE_EXPR. Return FALSE otherwise. */
-
-bool
-saved_expr_p (tree expr)
-{
- return TREE_CODE (skip_simple_arithmetic (expr)) == SAVE_EXPR;
-}
-
/* Arrange for an expression to be expanded multiple independent
times. This is useful for cleanup actions, as the backend can
expand them multiple times in different places. */
{
switch (code)
{
- case SAVE_EXPR:
- return 2;
case GOTO_SUBROUTINE_EXPR:
- case RTL_EXPR:
return 0;
case WITH_CLEANUP_EXPR:
return 2;
{
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' */
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 SSA_NAME: return TS_SSA_NAME;
case PLACEHOLDER_EXPR: return TS_COMMON;
+ case STATEMENT_LIST: return TS_STATEMENT_LIST;
+ case BLOCK: return TS_BLOCK;
+ case TREE_BINFO: return TS_BINFO;
+ case VALUE_HANDLE: return TS_VALUE_HANDLE;
default:
abort ();
{
switch (TREE_CODE (expr))
{
- case SAVE_EXPR:
- if (! SAVE_EXPR_PERSISTENT_P (expr))
- SAVE_EXPR_RTL (expr) = 0;
- break;
-
case TARGET_EXPR:
/* Don't mess with a TARGET_EXPR that hasn't been expanded.
It's OK for this to happen if it was part of a subtree that
TREE_OPERAND (expr, 3) = NULL_TREE;
break;
- case RTL_EXPR:
- /* I don't yet know how to emit a sequence multiple times. */
- if (RTL_EXPR_SEQUENCE (expr) != 0)
- abort ();
- break;
-
default:
break;
}
}
-/* 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.
SAVE_EXPRs basically *only* appear replicated in an expression tree,
occasionally across the whole of a function. It is therefore only
safe to unsave a SAVE_EXPR if you know that all occurrences appear
- below the UNSAVE_EXPR.
-
- RTL_EXPRs consume their rtl during evaluation. It is therefore
- never possible to unsave them. */
+ below the UNSAVE_EXPR. */
int
unsafe_for_reeval (tree expr)
switch (code)
{
case SAVE_EXPR:
- 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))
{
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;
case 't': /* a type node */
case 'x': /* something random, like an identifier or an ERROR_MARK. */
case 'd': /* A decl node */
- case 'b': /* A block node */
return 0;
case 'e': /* an expression */
contains_placeholder_p (tree exp)
{
enum tree_code code;
- int result;
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))
|| CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 2)));
- case SAVE_EXPR:
- /* If we already know this doesn't have a placeholder, don't
- check again. */
- if (SAVE_EXPR_NOPLACEHOLDER (exp) || SAVE_EXPR_RTL (exp) != 0)
- return 0;
-
- SAVE_EXPR_NOPLACEHOLDER (exp) = 1;
- result = CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 0));
- if (result)
- SAVE_EXPR_NOPLACEHOLDER (exp) = 0;
-
- 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));
}
return 0;
+ case DECL_EXPR:
+ return (DECL_INITIAL (DECL_EXPR_DECL (exp))
+ && has_cleanups (DECL_INITIAL (DECL_EXPR_DECL (exp))));
+
default:
break;
}
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),
+ NULL_TREE));
+ }
+ 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 ();
- }
+ TREE_READONLY (new) = TREE_READONLY (exp);
+ return new;
+}
- break;
+/* 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. */
- 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;
-
- 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':
+ 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
case COMPONENT_REF:
result = build_nt (COMPONENT_REF,
stabilize_reference (TREE_OPERAND (ref, 0)),
- TREE_OPERAND (ref, 1));
+ TREE_OPERAND (ref, 1), NULL_TREE);
break;
case BIT_FIELD_REF:
case ARRAY_REF:
result = build_nt (ARRAY_REF,
stabilize_reference (TREE_OPERAND (ref, 0)),
- stabilize_reference_1 (TREE_OPERAND (ref, 1)));
+ stabilize_reference_1 (TREE_OPERAND (ref, 1)),
+ TREE_OPERAND (ref, 2), TREE_OPERAND (ref, 3));
break;
case ARRAY_RANGE_REF:
result = build_nt (ARRAY_RANGE_REF,
stabilize_reference (TREE_OPERAND (ref, 0)),
- stabilize_reference_1 (TREE_OPERAND (ref, 1)));
+ stabilize_reference_1 (TREE_OPERAND (ref, 1)),
+ TREE_OPERAND (ref, 2), TREE_OPERAND (ref, 3));
break;
case COMPOUND_EXPR:
volatiles. */
return stabilize_reference_1 (ref);
- case RTL_EXPR:
- result = build1 (INDIRECT_REF, TREE_TYPE (ref),
- save_expr (build1 (ADDR_EXPR,
- build_pointer_type (TREE_TYPE (ref)),
- ref)));
- break;
-
/* If arg isn't a kind of lvalue we recognize, make no change.
Caller should recognize the error for an invalid lvalue. */
default:
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))
case 'x':
case 't':
case 'd':
- case 'b':
case '<':
case 's':
case 'e':
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. */
+\f
+/* Low-level constructors for expressions. */
+
+/* A helper function for build1 and constant folders. Set TREE_CONSTANT,
+ TREE_INVARIANT, and TREE_SIDE_EFFECTS for an ADDR_EXPR. */
+
+void
+recompute_tree_invarant_for_addr_expr (tree t)
+{
+ tree node;
+ bool tc = true, ti = true, se = false;
+
+ /* We started out assuming this address is both invariant and constant, but
+ does not have side effects. Now go down any handled components and see if
+ any of them involve offsets that are either non-constant or non-invariant.
+ Also check for side-effects.
+
+ ??? Note that this code makes no attempt to deal with the case where
+ taking the address of something causes a copy due to misalignment. */
+
+#define UPDATE_TITCSE(NODE) \
+do { tree _node = (NODE); \
+ if (_node && !TREE_INVARIANT (_node)) ti = false; \
+ if (_node && !TREE_CONSTANT (_node)) tc = false; \
+ if (_node && TREE_SIDE_EFFECTS (_node)) se = true; } while (0)
+
+ for (node = TREE_OPERAND (t, 0); handled_component_p (node);
+ node = TREE_OPERAND (node, 0))
+ {
+ /* If the first operand doesn't have an ARRAY_TYPE, this is a bogus
+ array reference (probably made temporarily by the G++ front end),
+ so ignore all the operands. */
+ if ((TREE_CODE (node) == ARRAY_REF
+ || TREE_CODE (node) == ARRAY_RANGE_REF)
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (node, 0))) == ARRAY_TYPE)
+ {
+ UPDATE_TITCSE (TREE_OPERAND (node, 1));
+ UPDATE_TITCSE (array_ref_low_bound (node));
+ UPDATE_TITCSE (array_ref_element_size (node));
+ }
+ /* Likewise, just because this is a COMPONENT_REF doesn't mean we have a
+ FIELD_DECL, apparently. The G++ front end can put something else
+ there, at least temporarily. */
+ else if (TREE_CODE (node) == COMPONENT_REF
+ && TREE_CODE (TREE_OPERAND (node, 1)) == FIELD_DECL)
+ UPDATE_TITCSE (component_ref_field_offset (node));
+ else if (TREE_CODE (node) == BIT_FIELD_REF)
+ UPDATE_TITCSE (TREE_OPERAND (node, 2));
+ }
+
+ /* Now see what's inside. If it's an INDIRECT_REF, copy our properties from
+ it. If it's a decl, it's invariant and constant if the decl is static.
+ It's also invariant if it's a decl in the current function. (Taking the
+ address of a volatile variable is not volatile.) If it's a constant,
+ the address is both invariant and constant. Otherwise it's neither. */
+ if (TREE_CODE (node) == INDIRECT_REF)
+ UPDATE_TITCSE (node);
+ else if (DECL_P (node))
+ {
+ if (staticp (node))
+ ;
+ else if (decl_function_context (node) == current_function_decl)
+ tc = false;
+ else
+ ti = tc = false;
+ }
+ else if (TREE_CODE_CLASS (TREE_CODE (node)) == 'c')
+ ;
+ else
+ {
+ ti = tc = false;
+ se |= TREE_SIDE_EFFECTS (node);
+ }
+
+ TREE_CONSTANT (t) = tc;
+ TREE_INVARIANT (t) = ti;
+ TREE_SIDE_EFFECTS (t) = se;
+#undef UPDATE_TITCSE
+}
/* Build an expression of code CODE, data type TYPE, and operands as
specified. Expressions and reference nodes can be created this way.
magic within the build macro. */
tree
-build0 (enum tree_code code, tree tt)
+build0_stat (enum tree_code code, tree tt MEM_STAT_DECL)
{
tree t;
abort ();
#endif
- t = make_node (code);
+ t = make_node_stat (code PASS_MEM_STAT);
TREE_TYPE (t) = tt;
return t;
}
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
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;
+#ifdef USE_MAPPED_LOCATION
+ SET_EXPR_LOCATION (t, UNKNOWN_LOCATION);
+#else
+ SET_EXPR_LOCUS (t, NULL);
+#endif
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);
case INIT_EXPR:
case MODIFY_EXPR:
case VA_ARG_EXPR:
- case RTL_EXPR:
case PREDECREMENT_EXPR:
case PREINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
case ADDR_EXPR:
if (node)
- {
- /* The address of a volatile decl or reference does not have
- side-effects. But be careful not to ignore side-effects from
- other sources deeper in the expression--if node is a _REF and
- one of its operands has side-effects, so do we. */
- if (TREE_THIS_VOLATILE (node))
- {
- TREE_SIDE_EFFECTS (t) = 0;
- if (!DECL_P (node))
- {
- int i = first_rtl_op (TREE_CODE (node)) - 1;
- for (; i >= 0; --i)
- {
- if (TREE_SIDE_EFFECTS (TREE_OPERAND (node, i)))
- TREE_SIDE_EFFECTS (t) = 1;
- }
- }
- }
- }
+ recompute_tree_invarant_for_addr_expr (t);
break;
default:
- if (TREE_CODE_CLASS (code) == '1' && node && TREE_CONSTANT (node))
+ 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;
+ if (TREE_CODE_CLASS (code) == 'r' && node && TREE_THIS_VOLATILE (node))
+ TREE_THIS_VOLATILE (t) = 1;
break;
}
#define PROCESS_ARG(N) \
do { \
TREE_OPERAND (t, N) = arg##N; \
- if (arg##N && fro > N) \
+ if (arg##N &&!TYPE_P (arg##N) && fro > N) \
{ \
if (TREE_SIDE_EFFECTS (arg##N)) \
side_effects = 1; \
read_only = 0; \
if (!TREE_CONSTANT (arg##N)) \
constant = 0; \
+ if (!TREE_INVARIANT (arg##N)) \
+ invariant = 0; \
} \
} while (0)
tree
-build2 (enum tree_code code, tree tt, tree arg0, tree arg1)
+build2_stat (enum tree_code code, tree tt, tree arg0, tree arg1 MEM_STAT_DECL)
{
- bool constant, read_only, side_effects;
+ bool constant, read_only, side_effects, invariant;
tree t;
int fro;
abort ();
#endif
- t = make_node (code);
+ t = make_node_stat (code PASS_MEM_STAT);
TREE_TYPE (t) = tt;
/* Below, we automatically set TREE_SIDE_EFFECTS and TREE_READONLY for the
|| TREE_CODE_CLASS (code) == '2');
read_only = 1;
side_effects = TREE_SIDE_EFFECTS (t);
+ invariant = constant;
PROCESS_ARG(0);
PROCESS_ARG(1);
- 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 = TREE_OPERAND (t, 1); node; node = TREE_CHAIN (node))
- if (TREE_SIDE_EFFECTS (TREE_VALUE (node)))
- {
- side_effects = 1;
- break;
- }
- }
-
TREE_READONLY (t) = read_only;
TREE_CONSTANT (t) = constant;
+ TREE_INVARIANT (t) = invariant;
TREE_SIDE_EFFECTS (t) = side_effects;
+ TREE_THIS_VOLATILE (t)
+ = TREE_CODE_CLASS (code) == 'r' && arg0 && TREE_THIS_VOLATILE (arg0);
return t;
}
tree
-build3 (enum tree_code code, tree tt, tree arg0, tree arg1, tree arg2)
+build3_stat (enum tree_code code, tree tt, tree arg0, tree arg1,
+ tree arg2 MEM_STAT_DECL)
{
- bool constant, read_only, side_effects;
+ bool constant, read_only, side_effects, invariant;
tree t;
int fro;
- /* ??? Quite a lot of existing code passes one too many arguments to
- CALL_EXPR. Not going to fix them, because CALL_EXPR is about to
- grow a new argument, so it would just mean changing them back. */
- if (code == CALL_EXPR)
- {
- if (arg2 != NULL_TREE)
- abort ();
- return build2 (code, tt, arg0, arg1);
- }
-
#ifdef ENABLE_CHECKING
if (TREE_CODE_LENGTH (code) != 3)
abort ();
#endif
- t = make_node (code);
+ t = make_node_stat (code PASS_MEM_STAT);
TREE_TYPE (t) = tt;
fro = first_rtl_op (code);
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;
+ TREE_THIS_VOLATILE (t)
+ = TREE_CODE_CLASS (code) == 'r' && arg0 && TREE_THIS_VOLATILE (arg0);
return t;
}
tree
-build4 (enum tree_code code, tree tt, tree arg0, tree arg1,
- tree arg2, tree arg3)
+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;
+ bool constant, read_only, side_effects, invariant;
tree t;
int fro;
abort ();
#endif
- t = make_node (code);
+ t = make_node_stat (code PASS_MEM_STAT);
TREE_TYPE (t) = tt;
fro = first_rtl_op (code);
PROCESS_ARG(3);
TREE_SIDE_EFFECTS (t) = side_effects;
+ TREE_THIS_VOLATILE (t)
+ = TREE_CODE_CLASS (code) == 'r' && arg0 && TREE_THIS_VOLATILE (arg0);
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). */
+#if 1 /* ! defined(USE_MAPPED_LOCATION) */
+/* ??? gengtype doesn't handle conditionals */
+static GTY(()) tree last_annotated_node;
+#endif
+
+#ifdef USE_MAPPED_LOCATION
-tree
-build_expr_wfl (tree node, const char *file, int line, int col)
+expanded_location
+expand_location (source_location loc)
{
- static const char *last_file = 0;
- static tree last_filenode = NULL_TREE;
- tree wfl = make_node (EXPR_WITH_FILE_LOCATION);
+ expanded_location xloc;
+ if (loc == 0) { xloc.file = NULL; xloc.line = 0; }
+ else
+ {
+ const struct line_map *map = linemap_lookup (&line_table, loc);
+ xloc.file = map->to_file;
+ xloc.line = SOURCE_LINE (map, loc);
+ };
+ return xloc;
+}
+
+#else
+
+/* 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);
}
+#endif
\f
/* Return a declaration like DDECL except that its DECL_ATTRIBUTES
is ATTRIBUTE. */
{
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;
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;
/* 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));
case BIT_AND_EXPR:
case BIT_XOR_EXPR:
case PLUS_EXPR:
- case MINUS_EXPR:
case MULT_EXPR:
- case LSHIFT_EXPR:
- case RSHIFT_EXPR:
case MIN_EXPR:
case MAX_EXPR:
return true;
case BIT_AND_EXPR:
case NE_EXPR:
case EQ_EXPR:
+ case UNORDERED_EXPR:
+ case ORDERED_EXPR:
+ case UNEQ_EXPR:
+ case LTGT_EXPR:
+ case TRUTH_AND_EXPR:
+ case TRUTH_XOR_EXPR:
+ case TRUTH_OR_EXPR:
return true;
default:
code = TREE_CODE (t);
class = TREE_CODE_CLASS (code);
- if (class == 'd')
+ if (class == 'd'
+ || TREE_CODE (t) == VALUE_HANDLE)
{
/* Decls we can just compare by pointer. */
val = iterative_hash_object (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);
+ {
+ unsigned int val2 = real_hash (TREE_REAL_CST_PTR (t));
+
+ val = iterative_hash (&val2, sizeof (unsigned int), val);
+ }
else if (code == STRING_CST)
val = iterative_hash (TREE_STRING_POINTER (t),
TREE_STRING_LENGTH (t), val);
{
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 (commutative_tree_code (code))
{
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))
{
tree t;
tree ptype;
- int hashcode;
+ int hashcode = 0;
/* Make a node of the sort we want. */
t = make_node (METHOD_TYPE);
argtypes = tree_cons (NULL_TREE, ptype, argtypes);
TYPE_ARG_TYPES (t) = argtypes;
- /* If we already have such a type, use the old one and free this one.
- Note that it also frees up the above cons cell if found. */
- hashcode = TYPE_HASH (basetype) + TYPE_HASH (rettype) +
- type_hash_list (argtypes);
-
+ /* If we already have such a type, use the old one. */
+ 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))
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))
- || TREE_UNSIGNED (TREE_TYPE (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
&& (for_type || ! DECL_BIT_FIELD (TREE_OPERAND (op, 1)))
&& (! uns || final_prec <= innerprec || unsignedp))
{
- win = build (COMPONENT_REF, type, TREE_OPERAND (op, 0),
- TREE_OPERAND (op, 1));
+ win = build3 (COMPONENT_REF, type, TREE_OPERAND (op, 0),
+ TREE_OPERAND (op, 1), NULL_TREE);
TREE_SIDE_EFFECTS (win) = TREE_SIDE_EFFECTS (op);
TREE_THIS_VOLATILE (win) = TREE_THIS_VOLATILE (op);
}
/* 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);
}
/* Since type_for_size always gives an integer type. */
&& TREE_CODE (TREE_TYPE (op)) != REAL_TYPE
/* Ensure field is laid out already. */
- && DECL_SIZE (TREE_OPERAND (op, 1)) != 0)
+ && DECL_SIZE (TREE_OPERAND (op, 1)) != 0
+ && host_integerp (DECL_SIZE (TREE_OPERAND (op, 1)), 1))
{
unsigned HOST_WIDE_INT innerprec
= tree_low_cst (DECL_SIZE (TREE_OPERAND (op, 1)), 1);
- int unsignedp = (TREE_UNSIGNED (TREE_OPERAND (op, 1))
- || TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op, 1))));
- tree type = (*lang_hooks.types.type_for_size) (innerprec, unsignedp);
+ 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));
- win = build (COMPONENT_REF, type, TREE_OPERAND (op, 0),
- TREE_OPERAND (op, 1));
+ uns = DECL_UNSIGNED (TREE_OPERAND (op, 1));
+ win = build3 (COMPONENT_REF, type, TREE_OPERAND (op, 0),
+ TREE_OPERAND (op, 1), NULL_TREE);
TREE_SIDE_EFFECTS (win) = TREE_SIDE_EFFECTS (op);
TREE_THIS_VOLATILE (win) = TREE_THIS_VOLATILE (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
}
}
+/* Subprogram of following function. Called by walk_tree.
+
+ Return *TP if it is an automatic variable or parameter of the
+ function passed in as DATA. */
+
+static tree
+find_var_from_fn (tree *tp, int *walk_subtrees, void *data)
+{
+ tree fn = (tree) data;
+
+ if (TYPE_P (*tp))
+ *walk_subtrees = 0;
+
+ else if (DECL_P (*tp) && lang_hooks.tree_inlining.auto_var_in_fn_p (*tp, fn))
+ return *tp;
+
+ return NULL_TREE;
+}
+
/* 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:
+ size. If FN is nonzero, only return true if a modifier of the type
+ or position of FN is a variable or parameter inside FN.
+
+ 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 (tree type)
+variably_modified_type_p (tree type, tree fn)
{
tree t;
+/* Test if T is either variable (if FN is zero) or an expression containing
+ a variable in FN. */
+#define RETURN_TRUE_IF_VAR(T) \
+ do { tree _t = (T); \
+ if (_t && _t != error_mark_node && TREE_CODE (_t) != INTEGER_CST \
+ && (!fn || walk_tree (&_t, find_var_from_fn, fn, NULL))) \
+ return true; } while (0)
+
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. */
- t = TYPE_SIZE (type);
- if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST)
- return true;
+ RETURN_TRUE_IF_VAR (TYPE_SIZE (type));
+ RETURN_TRUE_IF_VAR (TYPE_SIZE_UNIT(type));
switch (TREE_CODE (type))
{
case POINTER_TYPE:
case REFERENCE_TYPE:
case ARRAY_TYPE:
- /* If TYPE is a pointer or reference, it is variably modified if
- the type pointed to is variably modified. Similarly for arrays;
- note that VLAs are handled by the TYPE_SIZE check above. */
- return variably_modified_type_p (TREE_TYPE (type));
+ case SET_TYPE:
+ case VECTOR_TYPE:
+ if (variably_modified_type_p (TREE_TYPE (type), fn))
+ return true;
+ 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. */
- {
- tree parm;
+ if (variably_modified_type_p (TREE_TYPE (type), fn))
+ return true;
- if (variably_modified_type_p (TREE_TYPE (type)))
+ for (t = TYPE_ARG_TYPES (type);
+ t && t != void_list_node;
+ t = TREE_CHAIN (t))
+ if (variably_modified_type_p (TREE_VALUE (t), fn))
return true;
- for (parm = TYPE_ARG_TYPES (type);
- parm && parm != void_list_node;
- parm = TREE_CHAIN (parm))
- if (variably_modified_type_p (TREE_VALUE (parm)))
- return true;
- }
break;
case INTEGER_TYPE:
+ 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;
- return false;
+ RETURN_TRUE_IF_VAR (TYPE_MIN_VALUE (type));
+ RETURN_TRUE_IF_VAR (TYPE_MAX_VALUE (type));
+ 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)
+ {
+ RETURN_TRUE_IF_VAR (DECL_FIELD_OFFSET (t));
+ RETURN_TRUE_IF_VAR (DECL_SIZE (t));
+ RETURN_TRUE_IF_VAR (DECL_SIZE_UNIT (t));
+
+ if (TREE_CODE (type) == QUAL_UNION_TYPE)
+ RETURN_TRUE_IF_VAR (DECL_QUALIFIER (t));
+ }
+ 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, fn);
+
+#undef RETURN_TRUE_IF_VAR
}
/* Given a DECL or TYPE, return the scope in which it was declared, or
if (TREE_CODE (decl) == ERROR_MARK)
return 0;
- if (TREE_CODE (decl) == SAVE_EXPR)
- context = SAVE_EXPR_CONTEXT (decl);
-
/* C++ virtual functions use DECL_CONTEXT for the class of the vtable
where we look up the function at runtime. Such functions always take
a first argument of type 'pointer to real context'.
/* We couldn't figure out what was being called. Maybe the front
end has some idea. */
- return (*lang_hooks.lang_get_callee_fndecl) (call);
+ return lang_hooks.lang_get_callee_fndecl (call);
}
/* Print debugging information about tree nodes generated during the compile,
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"
}
\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. */
+
+/* Complain that the tree code of NODE does not match the expected 0
+ terminated list of trailing codes. FILE, LINE, and FUNCTION are of
+ the caller. */
void
-tree_check_failed (const tree node, enum tree_code code, const char *file,
- int line, const char *function)
-{
+tree_check_failed (const tree node, const char *file,
+ int line, const char *function, ...)
+{
+ va_list args;
+ char *buffer;
+ unsigned length = 0;
+ int code;
+
+ va_start (args, function);
+ while ((code = va_arg (args, int)))
+ length += 4 + strlen (tree_code_name[code]);
+ va_end (args);
+ va_start (args, function);
+ buffer = alloca (length);
+ length = 0;
+ while ((code = va_arg (args, int)))
+ {
+ if (length)
+ {
+ strcpy (buffer + length, " or ");
+ length += 4;
+ }
+ strcpy (buffer + length, tree_code_name[code]);
+ length += strlen (tree_code_name[code]);
+ }
+ va_end (args);
+
internal_error ("tree check: expected %s, have %s in %s, at %s:%d",
- tree_code_name[code], tree_code_name[TREE_CODE (node)],
+ buffer, tree_code_name[TREE_CODE (node)],
+ function, trim_filename (file), line);
+}
+
+/* Complain that the tree code of NODE does match the expected 0
+ terminated list of trailing codes. FILE, LINE, and FUNCTION are of
+ the caller. */
+
+void
+tree_not_check_failed (const tree node, const char *file,
+ int line, const char *function, ...)
+{
+ va_list args;
+ char *buffer;
+ unsigned length = 0;
+ int code;
+
+ va_start (args, function);
+ while ((code = va_arg (args, int)))
+ length += 4 + strlen (tree_code_name[code]);
+ va_end (args);
+ va_start (args, function);
+ buffer = alloca (length);
+ length = 0;
+ while ((code = va_arg (args, int)))
+ {
+ if (length)
+ {
+ strcpy (buffer + length, " or ");
+ length += 4;
+ }
+ strcpy (buffer + length, tree_code_name[code]);
+ length += strlen (tree_code_name[code]);
+ }
+ va_end (args);
+
+ internal_error ("tree check: expected none of %s, have %s in %s, at %s:%d",
+ buffer, tree_code_name[TREE_CODE (node)],
function, trim_filename (file), line);
}
-/* Similar to above, except that we check for a class of tree
+/* 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 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. */
void
build_common_tree_nodes (int signed_char)
{
+ /* This function is called after command line parsing is complete,
+ but before any DECL nodes should have been created. Therefore,
+ now is the appropriate time to adjust next_decl_uid so that the
+ range 0 .. num_in_fnames-1 is reserved for TRANSLATION_UNIT_DECLs. */
+ if (next_decl_uid)
+ abort ();
+ next_decl_uid = num_in_fnames;
+
error_mark_node = make_node (ERROR_MARK);
TREE_TYPE (error_mark_node) = error_mark_node;
TREE_TYPE (TYPE_MAX_VALUE (boolean_type_node)) = boolean_type_node;
TYPE_PRECISION (boolean_type_node) = 1;
- intQI_type_node = make_signed_type (GET_MODE_BITSIZE (QImode));
- intHI_type_node = make_signed_type (GET_MODE_BITSIZE (HImode));
- intSI_type_node = make_signed_type (GET_MODE_BITSIZE (SImode));
- 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));
+ /* 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");
ptr_type_node = build_pointer_type (void_type_node);
const_ptr_type_node
= build_pointer_type (build_type_variant (void_type_node, 1, 0));
+ fileptr_type_node = ptr_type_node;
float_type_node = make_node (REAL_TYPE);
TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE;
layout_type (complex_long_double_type_node);
{
- tree t = (*targetm.build_builtin_va_list) ();
+ 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);
- V4DF_type_node = make_vector (V4DFmode, double_type_node, 0);
}
/* HACK. GROSS. This is absolutely disgusting. I wish there was a
else
return bottom;
- TREE_READONLY (outer) = TREE_READONLY (type);
- TREE_THIS_VOLATILE (outer) = TREE_THIS_VOLATILE (type);
+ TYPE_READONLY (outer) = TYPE_READONLY (type);
+ TYPE_VOLATILE (outer) = TYPE_VOLATILE (type);
return outer;
}
-/* Returns a vector tree node given a vector mode, the inner type, and
- the signness. */
-
+/* Returns a vector tree node given a vector mode and inner type. */
tree
-make_vector (enum machine_mode mode, tree innertype, int unsignedp)
+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 CONSTRUCTOR:
- {
- /* Set is empty if it has no elements. */
- if ((TREE_CODE (TREE_TYPE (init)) == SET_TYPE)
- && CONSTRUCTOR_ELTS (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;
- 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;
- }
+ case CONSTRUCTOR:
+ 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);
+}
+
+
+/* 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"