#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);
"perm_tree_lists",
"temp_tree_lists",
"vecs",
+ "phi_nodes",
+ "ssa names",
"random kinds",
"lang_decl kinds",
"lang_type kinds"
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);
}
#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;
/* 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':
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_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;
}
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;
}
|| 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;
}
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,
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)
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;
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))
{
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;
+ case 1:
+ op0 = SUBSTITUTE_IN_EXPR (TREE_OPERAND (exp, 0), f, r);
+ if (op0 == TREE_OPERAND (exp, 0))
+ return exp;
- new = fold (build1 (code, TREE_TYPE (exp), op0));
- break;
-
- 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. */
+/* A helper function for build1 and constant folders.
+ Set TREE_CONSTANT and TREE_INVARIANT for an ADDR_EXPR. */
+
+void
+recompute_tree_invarant_for_addr_expr (tree t)
+{
+ tree node = TREE_OPERAND (t, 0);
+ bool tc = false, ti = false;
+
+ /* Addresses of constants and static variables are constant;
+ all other decl addresses are invariant. */
+ if (staticp (node))
+ tc = ti = true;
+ else
+ {
+ /* Step past constant offsets. */
+ while (1)
+ {
+ 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;
+ }
+
+ TREE_CONSTANT (t) = tc;
+ TREE_INVARIANT (t) = ti;
+}
+
/* 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_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);
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
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;
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_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;
|| 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;
return t;
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 ();
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;
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;
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
/* 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. */
/* 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.
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;
{
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;
+
+ /* 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. */
- if (t != 0 && mode == ptr_mode)
- return t;
+ 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;
-
- /* We can only record one type as "the" pointer to TO_TYPE. We choose to
- record the pointer whose mode is ptr_mode. */
- if (mode == ptr_mode)
- TYPE_POINTER_TO (to_type) = t;
+ 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. */
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);
}
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 = iterative_hash_object (TYPE_HASH (elt_type), hashcode);
hashcode = iterative_hash_object (TYPE_HASH (index_type), hashcode);
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. */
+ /* 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);
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. */
+ /* 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))
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. */
+ /* 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);
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. */
+ /* 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);
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))));
+ 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.
/* 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);
- int unsignedp = (TREE_UNSIGNED (TREE_OPERAND (op, 1))
- || TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op, 1))));
+ 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,
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
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)))
+ 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)))
+ 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)))
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;
+ 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;
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
}
\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. */
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");
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);
+}
+
+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"