{
switch (code)
{
- case GOTO_SUBROUTINE_EXPR:
- return 0;
- case WITH_CLEANUP_EXPR:
- return 2;
default:
return TREE_CODE_LENGTH (code);
}
switch (TREE_CODE (exp))
{
case TARGET_EXPR:
- case GOTO_SUBROUTINE_EXPR:
case WITH_CLEANUP_EXPR:
return 1;
}
/* 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')
;
expand_location (source_location loc)
{
expanded_location xloc;
- if (loc == 0) { xloc.file = NULL; xloc.line = 0; }
+ if (loc == 0) { xloc.file = NULL; xloc.line = 0; xloc.column = 0; }
else
{
const struct line_map *map = linemap_lookup (&line_table, loc);
xloc.file = map->to_file;
xloc.line = SOURCE_LINE (map, loc);
+ xloc.column = SOURCE_COLUMN (map, loc);
};
return xloc;
}
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
}
+/* Returns true if it is possible to prove that the index of
+ an array access REF (an ARRAY_REF expression) falls into the
+ array bounds. */
+
+bool
+in_array_bounds_p (tree ref)
+{
+ tree idx = TREE_OPERAND (ref, 1);
+ tree min, max;
+
+ if (TREE_CODE (idx) != INTEGER_CST)
+ return false;
+
+ min = array_ref_low_bound (ref);
+ max = array_ref_up_bound (ref);
+ if (!min
+ || !max
+ || TREE_CODE (min) != INTEGER_CST
+ || TREE_CODE (max) != INTEGER_CST)
+ return false;
+
+ if (tree_int_cst_lt (idx, min)
+ || tree_int_cst_lt (max, idx))
+ return false;
+
+ return true;
+}
+
/* Return true if T (assumed to be a DECL) must be assigned a memory
location. */
|| decl_function_context (t) != current_function_decl);
}
+/* There are situations in which a language considers record types
+ compatible which have different field lists. Decide if two fields
+ are compatible. It is assumed that the parent records are compatible. */
+
+bool
+fields_compatible_p (tree f1, tree f2)
+{
+ if (!operand_equal_p (DECL_FIELD_BIT_OFFSET (f1),
+ DECL_FIELD_BIT_OFFSET (f2), OEP_ONLY_CONST))
+ return false;
+
+ if (!operand_equal_p (DECL_FIELD_OFFSET (f1),
+ DECL_FIELD_OFFSET (f2), OEP_ONLY_CONST))
+ return false;
+
+ if (!lang_hooks.types_compatible_p (TREE_TYPE (f1), TREE_TYPE (f2)))
+ return false;
+
+ return true;
+}
+
+/* Locate within RECORD a field that is compatible with ORIG_FIELD. */
+
+tree
+find_compatible_field (tree record, tree orig_field)
+{
+ tree f;
+
+ for (f = TYPE_FIELDS (record); f ; f = TREE_CHAIN (f))
+ if (TREE_CODE (f) == FIELD_DECL
+ && fields_compatible_p (f, orig_field))
+ return f;
+
+ /* ??? Why isn't this on the main fields list? */
+ f = TYPE_VFIELD (record);
+ if (f && TREE_CODE (f) == FIELD_DECL
+ && fields_compatible_p (f, orig_field))
+ return f;
+
+ /* ??? We should abort here, but Java appears to do Bad Things
+ with inherited fields. */
+ return orig_field;
+}
+
+/* Return value of a constant X. */
+
+HOST_WIDE_INT
+int_cst_value (tree x)
+{
+ unsigned bits = TYPE_PRECISION (TREE_TYPE (x));
+ unsigned HOST_WIDE_INT val = TREE_INT_CST_LOW (x);
+ bool negative = ((val >> (bits - 1)) & 1) != 0;
+
+ if (bits > HOST_BITS_PER_WIDE_INT)
+ abort ();
+
+ if (negative)
+ val |= (~(unsigned HOST_WIDE_INT) 0) << (bits - 1) << 1;
+ else
+ val &= ~((~(unsigned HOST_WIDE_INT) 0) << (bits - 1) << 1);
+
+ return val;
+}
+
+/* Returns the greatest common divisor of A and B, which must be
+ INTEGER_CSTs. */
+
+tree
+tree_fold_gcd (tree a, tree b)
+{
+ tree a_mod_b;
+ tree type = TREE_TYPE (a);
+
+#if defined ENABLE_CHECKING
+ if (TREE_CODE (a) != INTEGER_CST
+ || TREE_CODE (b) != INTEGER_CST)
+ abort ();
+#endif
+
+ if (integer_zerop (a))
+ return b;
+
+ if (integer_zerop (b))
+ return a;
+
+ if (tree_int_cst_sgn (a) == -1)
+ a = fold (build (MULT_EXPR, type, a,
+ convert (type, integer_minus_one_node)));
+
+ if (tree_int_cst_sgn (b) == -1)
+ b = fold (build (MULT_EXPR, type, b,
+ convert (type, integer_minus_one_node)));
+
+ while (1)
+ {
+ a_mod_b = fold (build (CEIL_MOD_EXPR, type, a, b));
+
+ if (!TREE_INT_CST_LOW (a_mod_b)
+ && !TREE_INT_CST_HIGH (a_mod_b))
+ return b;
+
+ a = b;
+ b = a_mod_b;
+ }
+}
+
#include "gt-tree.h"