"perm_tree_lists",
"temp_tree_lists",
"vecs",
+ "binfos",
"phi_nodes",
"ssa names",
"random 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
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)
case INIT_EXPR:
case MODIFY_EXPR:
case VA_ARG_EXPR:
- case RTL_EXPR:
case PREDECREMENT_EXPR:
case PREINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
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
if (contains_placeholder_p (inner))
return t;
- t = build3 (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
{
switch (code)
{
- case SAVE_EXPR:
- return 2;
- case GOTO_SUBROUTINE_EXPR:
- case RTL_EXPR:
- return 0;
- case WITH_CLEANUP_EXPR:
- return 2;
default:
return TREE_CODE_LENGTH (code);
}
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:
{
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;
}
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. */
contains_placeholder_p (tree exp)
{
enum tree_code code;
- int result;
if (!exp)
return 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;
-
default:
break;
}
switch (TREE_CODE (exp))
{
case TARGET_EXPR:
- case GOTO_SUBROUTINE_EXPR:
case WITH_CLEANUP_EXPR:
return 1;
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:
}
/* Now see what's inside. If it's an INDIRECT_REF, copy our properties from
- it. If it's a decl, it's definitely invariant and it's constant if the
- decl is static. (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. */
+ 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))
+ 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')
;
case INIT_EXPR:
case MODIFY_EXPR:
case VA_ARG_EXPR:
- case RTL_EXPR:
case PREDECREMENT_EXPR:
case PREINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
|| 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),
+ || tree_int_cst_equal (TYPE_MIN_VALUE (a->type),
TYPE_MIN_VALUE (b->type))));
case OFFSET_TYPE:
return itype;
}
+/* Builds a signed or unsigned integer type of precision PRECISION.
+ Used for C bitfields whose precision does not match that of
+ built-in target types. */
+tree
+build_nonstandard_integer_type (unsigned HOST_WIDE_INT precision,
+ int unsignedp)
+{
+ tree itype = make_node (INTEGER_TYPE);
+
+ TYPE_PRECISION (itype) = precision;
+
+ if (unsignedp)
+ fixup_unsigned_type (itype);
+ else
+ fixup_signed_type (itype);
+
+ if (host_integerp (TYPE_MAX_VALUE (itype), 1))
+ return type_hash_canon (tree_low_cst (TYPE_MAX_VALUE (itype), 1), itype);
+
+ return itype;
+}
+
/* Create a range of some discrete type TYPE (an INTEGER_TYPE,
ENUMERAL_TYPE, BOOLEAN_TYPE, or CHAR_TYPE), with
low bound LOWVAL and high bound HIGHVAL.
int uns = 0;
int first = 1;
tree win = op;
+ bool integral_p = INTEGRAL_TYPE_P (TREE_TYPE (op));
while (TREE_CODE (op) == NOP_EXPR)
{
uns = TYPE_UNSIGNED (TREE_TYPE (op));
first = 0;
op = TREE_OPERAND (op, 0);
+ /* Keep trying to narrow, but don't assign op to win if it
+ would turn an integral type into something else. */
+ if (INTEGRAL_TYPE_P (TREE_TYPE (op)) != integral_p)
+ continue;
}
win = op;
}
}
+/* 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 ARRAY_TYPE:
case SET_TYPE:
case VECTOR_TYPE:
- if (variably_modified_type_p (TREE_TYPE (type)))
+ if (variably_modified_type_p (TREE_TYPE (type), fn))
return true;
break;
case METHOD_TYPE:
/* If TYPE is a function type, it is variably modified if any of the
parameters or the return type are variably modified. */
- if (variably_modified_type_p (TREE_TYPE (type)))
+ if (variably_modified_type_p (TREE_TYPE (type), fn))
return true;
for (t = TYPE_ARG_TYPES (type);
t && t != void_list_node;
t = TREE_CHAIN (t))
- if (variably_modified_type_p (TREE_VALUE (t)))
+ if (variably_modified_type_p (TREE_VALUE (t), fn))
return true;
break;
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_TRUE_IF_VAR (TYPE_MIN_VALUE (type));
+ RETURN_TRUE_IF_VAR (TYPE_MAX_VALUE (type));
break;
case RECORD_TYPE:
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;
+ RETURN_TRUE_IF_VAR (DECL_FIELD_OFFSET (t));
+ RETURN_TRUE_IF_VAR (DECL_SIZE (t));
+ RETURN_TRUE_IF_VAR (DECL_SIZE_UNIT (t));
- t1 = DECL_SIZE (t);
- if (t1 && t1 != error_mark_node && TREE_CODE (t1) != INTEGER_CST)
- return true;
+ if (TREE_CODE (type) == QUAL_UNION_TYPE)
+ RETURN_TRUE_IF_VAR (DECL_QUALIFIER (t));
}
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'.