/* Language-independent node constructors for parse phase of GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
- Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+ 2011 Free Software Foundation, Inc.
This file is part of GCC.
#include "toplev.h"
#include "ggc.h"
#include "hashtab.h"
+#include "filenames.h"
#include "output.h"
#include "target.h"
+#include "common/common-target.h"
#include "langhooks.h"
#include "tree-inline.h"
#include "tree-iterator.h"
#ifdef GATHER_STATISTICS
/* Statistics-gathering stuff. */
+static int tree_code_counts[MAX_TREE_CODES];
int tree_node_counts[(int) all_kinds];
int tree_node_sizes[(int) all_kinds];
static GTY ((if_marked ("tree_decl_map_marked_p"), param_is (struct tree_decl_map)))
htab_t value_expr_for_decl;
+static GTY ((if_marked ("tree_vec_map_marked_p"), param_is (struct tree_vec_map)))
+ htab_t debug_args_for_decl;
+
static GTY ((if_marked ("tree_priority_map_marked_p"),
param_is (struct tree_priority_map)))
htab_t init_priority_for_decl;
0, /* OMP_CLAUSE_ORDERED */
0, /* OMP_CLAUSE_DEFAULT */
3, /* OMP_CLAUSE_COLLAPSE */
- 0 /* OMP_CLAUSE_UNTIED */
+ 0, /* OMP_CLAUSE_UNTIED */
+ 1, /* OMP_CLAUSE_FINAL */
+ 0 /* OMP_CLAUSE_MERGEABLE */
};
const char * const omp_clause_code_name[] =
"ordered",
"default",
"collapse",
- "untied"
+ "untied",
+ "final",
+ "mergeable"
};
return TS_TYPE_DECL;
case FUNCTION_DECL:
return TS_FUNCTION_DECL;
+ case TRANSLATION_UNIT_DECL:
+ return TS_TRANSLATION_UNIT_DECL;
default:
return TS_DECL_NON_COMMON;
}
}
case tcc_type:
- return TS_TYPE;
+ return TS_TYPE_NON_COMMON;
case tcc_reference:
case tcc_comparison:
case tcc_unary:
{
unsigned i;
-#define MARK_TS_BASE(C) \
- do { \
- tree_contains_struct[C][TS_BASE] = 1; \
- } while (0)
-
-#define MARK_TS_COMMON(C) \
- do { \
- MARK_TS_BASE (C); \
- tree_contains_struct[C][TS_COMMON] = 1; \
- } while (0)
-
-#define MARK_TS_DECL_MINIMAL(C) \
- do { \
- MARK_TS_COMMON (C); \
- tree_contains_struct[C][TS_DECL_MINIMAL] = 1; \
- } while (0)
-
-#define MARK_TS_DECL_COMMON(C) \
- do { \
- MARK_TS_DECL_MINIMAL (C); \
- tree_contains_struct[C][TS_DECL_COMMON] = 1; \
- } while (0)
-
-#define MARK_TS_DECL_WRTL(C) \
- do { \
- MARK_TS_DECL_COMMON (C); \
- tree_contains_struct[C][TS_DECL_WRTL] = 1; \
- } while (0)
-
-#define MARK_TS_DECL_WITH_VIS(C) \
- do { \
- MARK_TS_DECL_WRTL (C); \
- tree_contains_struct[C][TS_DECL_WITH_VIS] = 1; \
- } while (0)
-
-#define MARK_TS_DECL_NON_COMMON(C) \
- do { \
- MARK_TS_DECL_WITH_VIS (C); \
- tree_contains_struct[C][TS_DECL_NON_COMMON] = 1; \
- } while (0)
-
for (i = ERROR_MARK; i < LAST_AND_UNUSED_TREE_CODE; i++)
{
enum tree_code code;
/* Mark all the structures that TS is derived from. */
switch (ts_code)
{
- case TS_COMMON:
+ case TS_TYPED:
+ case TS_BLOCK:
MARK_TS_BASE (code);
break;
+ case TS_COMMON:
case TS_INT_CST:
case TS_REAL_CST:
case TS_FIXED_CST:
case TS_VECTOR:
case TS_STRING:
case TS_COMPLEX:
+ case TS_SSA_NAME:
+ case TS_CONSTRUCTOR:
+ case TS_EXP:
+ case TS_STATEMENT_LIST:
+ MARK_TS_TYPED (code);
+ break;
+
case TS_IDENTIFIER:
case TS_DECL_MINIMAL:
- case TS_TYPE:
+ case TS_TYPE_COMMON:
case TS_LIST:
case TS_VEC:
- case TS_EXP:
- case TS_SSA_NAME:
- case TS_BLOCK:
case TS_BINFO:
- case TS_STATEMENT_LIST:
- case TS_CONSTRUCTOR:
case TS_OMP_CLAUSE:
case TS_OPTIMIZATION:
case TS_TARGET_OPTION:
MARK_TS_COMMON (code);
break;
+ case TS_TYPE_WITH_LANG_SPECIFIC:
+ MARK_TS_TYPE_COMMON (code);
+ break;
+
+ case TS_TYPE_NON_COMMON:
+ MARK_TS_TYPE_WITH_LANG_SPECIFIC (code);
+ break;
+
case TS_DECL_COMMON:
MARK_TS_DECL_MINIMAL (code);
break;
case TS_DECL_WRTL:
+ case TS_CONST_DECL:
MARK_TS_DECL_COMMON (code);
break;
case TS_PARM_DECL:
case TS_LABEL_DECL:
case TS_RESULT_DECL:
- case TS_CONST_DECL:
MARK_TS_DECL_WRTL (code);
break;
MARK_TS_DECL_NON_COMMON (code);
break;
+ case TS_TRANSLATION_UNIT_DECL:
+ MARK_TS_DECL_COMMON (code);
+ break;
+
default:
gcc_unreachable ();
}
/* Basic consistency checks for attributes used in fold. */
gcc_assert (tree_contains_struct[FUNCTION_DECL][TS_DECL_NON_COMMON]);
- gcc_assert (tree_contains_struct[TRANSLATION_UNIT_DECL][TS_DECL_NON_COMMON]);
gcc_assert (tree_contains_struct[TYPE_DECL][TS_DECL_NON_COMMON]);
gcc_assert (tree_contains_struct[CONST_DECL][TS_DECL_COMMON]);
gcc_assert (tree_contains_struct[VAR_DECL][TS_DECL_COMMON]);
gcc_assert (tree_contains_struct[TRANSLATION_UNIT_DECL][TS_DECL_COMMON]);
gcc_assert (tree_contains_struct[LABEL_DECL][TS_DECL_COMMON]);
gcc_assert (tree_contains_struct[FIELD_DECL][TS_DECL_COMMON]);
- gcc_assert (tree_contains_struct[CONST_DECL][TS_DECL_WRTL]);
gcc_assert (tree_contains_struct[VAR_DECL][TS_DECL_WRTL]);
gcc_assert (tree_contains_struct[PARM_DECL][TS_DECL_WRTL]);
gcc_assert (tree_contains_struct[RESULT_DECL][TS_DECL_WRTL]);
gcc_assert (tree_contains_struct[VAR_DECL][TS_DECL_WITH_VIS]);
gcc_assert (tree_contains_struct[FUNCTION_DECL][TS_DECL_WITH_VIS]);
gcc_assert (tree_contains_struct[TYPE_DECL][TS_DECL_WITH_VIS]);
- gcc_assert (tree_contains_struct[TRANSLATION_UNIT_DECL][TS_DECL_WITH_VIS]);
gcc_assert (tree_contains_struct[VAR_DECL][TS_VAR_DECL]);
gcc_assert (tree_contains_struct[FIELD_DECL][TS_FIELD_DECL]);
gcc_assert (tree_contains_struct[PARM_DECL][TS_PARM_DECL]);
gcc_assert (tree_contains_struct[FUNCTION_DECL][TS_FUNCTION_DECL]);
gcc_assert (tree_contains_struct[IMPORTED_DECL][TS_DECL_MINIMAL]);
gcc_assert (tree_contains_struct[IMPORTED_DECL][TS_DECL_COMMON]);
-
-#undef MARK_TS_BASE
-#undef MARK_TS_COMMON
-#undef MARK_TS_DECL_MINIMAL
-#undef MARK_TS_DECL_COMMON
-#undef MARK_TS_DECL_WRTL
-#undef MARK_TS_DECL_WITH_VIS
-#undef MARK_TS_DECL_NON_COMMON
}
}
case tcc_type: /* a type node */
- return sizeof (struct tree_type);
+ return sizeof (struct tree_type_non_common);
case tcc_reference: /* a reference */
case tcc_expression: /* an expression */
}
}
-/* Return a newly allocated node of code CODE. For decl and type
- nodes, some other fields are initialized. The rest of the node is
- initialized to zero. This function cannot be used for TREE_VEC or
- OMP_CLAUSE nodes, which is enforced by asserts in tree_code_size.
-
- Achoo! I got a code in the node. */
+/* Record interesting allocation statistics for a tree node with CODE
+ and LENGTH. */
-tree
-make_node_stat (enum tree_code code MEM_STAT_DECL)
+static void
+record_node_allocation_statistics (enum tree_code code ATTRIBUTE_UNUSED,
+ size_t length ATTRIBUTE_UNUSED)
{
- tree t;
- enum tree_code_class type = TREE_CODE_CLASS (code);
- size_t length = tree_code_size (code);
#ifdef GATHER_STATISTICS
+ enum tree_code_class type = TREE_CODE_CLASS (code);
tree_node_kind kind;
switch (type)
kind = constr_kind;
break;
+ case OMP_CLAUSE:
+ kind = omp_clause_kind;
+ break;
+
default:
kind = x_kind;
break;
}
break;
+ case tcc_vl_exp:
+ kind = e_kind;
+ break;
+
default:
gcc_unreachable ();
}
+ tree_code_counts[(int) code]++;
tree_node_counts[(int) kind]++;
tree_node_sizes[(int) kind] += length;
#endif
+}
+
+/* Allocate and return a new UID from the DECL_UID namespace. */
+
+int
+allocate_decl_uid (void)
+{
+ return next_decl_uid++;
+}
+
+/* Return a newly allocated node of code CODE. For decl and type
+ nodes, some other fields are initialized. The rest of the node is
+ initialized to zero. This function cannot be used for TREE_VEC or
+ OMP_CLAUSE nodes, which is enforced by asserts in tree_code_size.
+
+ Achoo! I got a code in the node. */
+
+tree
+make_node_stat (enum tree_code code MEM_STAT_DECL)
+{
+ tree t;
+ enum tree_code_class type = TREE_CODE_CLASS (code);
+ size_t length = tree_code_size (code);
+
+ record_node_allocation_statistics (code, length);
t = ggc_alloc_zone_cleared_tree_node_stat (
(code == IDENTIFIER_NODE) ? &tree_id_zone : &tree_zone,
DECL_UID (t) = --next_debug_decl_uid;
else
{
- DECL_UID (t) = next_decl_uid++;
+ DECL_UID (t) = allocate_decl_uid ();
SET_DECL_PT_UID (t, -1);
}
if (TREE_CODE (t) == LABEL_DECL)
}
\f
/* Return a new node with the same contents as NODE except that its
- TREE_CHAIN is zero and it has a fresh uid. */
+ TREE_CHAIN, if it has one, is zero and it has a fresh uid. */
tree
copy_node_stat (tree node MEM_STAT_DECL)
gcc_assert (code != STATEMENT_LIST);
length = tree_size (node);
+ record_node_allocation_statistics (code, length);
t = ggc_alloc_zone_tree_node_stat (&tree_zone, length PASS_MEM_STAT);
memcpy (t, node, length);
- TREE_CHAIN (t) = 0;
+ if (CODE_CONTAINS_STRUCT (code, TS_COMMON))
+ TREE_CHAIN (t) = 0;
TREE_ASM_WRITTEN (t) = 0;
TREE_VISITED (t) = 0;
if (code == VAR_DECL || code == PARM_DECL || code == RESULT_DECL)
DECL_UID (t) = --next_debug_decl_uid;
else
{
- DECL_UID (t) = next_decl_uid++;
+ DECL_UID (t) = allocate_decl_uid ();
if (DECL_PT_UID_SET_P (node))
SET_DECL_PT_UID (t, DECL_PT_UID (node));
}
}
\f
-/* Create an INT_CST node with a LOW value sign extended. */
+/* Create an INT_CST node with a LOW value sign extended to TYPE. */
tree
build_int_cst (tree type, HOST_WIDE_INT low)
if (!type)
type = integer_type_node;
- return build_int_cst_wide (type, low, low < 0 ? -1 : 0);
+ return double_int_to_tree (type, shwi_to_double_int (low));
}
-/* Create an INT_CST node with a LOW value in TYPE. The value is sign extended
- if it is negative. This function is similar to build_int_cst, but
- the extra bits outside of the type precision are cleared. Constants
- with these extra bits may confuse the fold so that it detects overflows
- even in cases when they do not occur, and in general should be avoided.
- We cannot however make this a default behavior of build_int_cst without
- more intrusive changes, since there are parts of gcc that rely on the extra
- precision of the integer constants. */
+/* Create an INT_CST node with a LOW value sign extended to TYPE. */
tree
build_int_cst_type (tree type, HOST_WIDE_INT low)
switch (TREE_CODE (type))
{
+ case NULLPTR_TYPE:
+ gcc_assert (hi == 0 && low == 0);
+ /* Fallthru. */
+
case POINTER_TYPE:
case REFERENCE_TYPE:
/* Cache NULL pointer. */
list = tree_cons (NULL_TREE, value, list);
for (; idx < TYPE_VECTOR_SUBPARTS (type); ++idx)
list = tree_cons (NULL_TREE,
- fold_convert (TREE_TYPE (type), integer_zero_node), list);
+ build_zero_cst (TREE_TYPE (type)), list);
return build_vector (type, nreverse (list));
}
+/* Build a vector of type VECTYPE where all the elements are SCs. */
+tree
+build_vector_from_val (tree vectype, tree sc)
+{
+ int i, nunits = TYPE_VECTOR_SUBPARTS (vectype);
+ VEC(constructor_elt, gc) *v = NULL;
+
+ if (sc == error_mark_node)
+ return sc;
+
+ /* Verify that the vector type is suitable for SC. Note that there
+ is some inconsistency in the type-system with respect to restrict
+ qualifications of pointers. Vector types always have a main-variant
+ element type and the qualification is applied to the vector-type.
+ So TREE_TYPE (vector-type) does not return a properly qualified
+ vector element-type. */
+ gcc_checking_assert (types_compatible_p (TYPE_MAIN_VARIANT (TREE_TYPE (sc)),
+ TREE_TYPE (vectype)));
+
+ v = VEC_alloc (constructor_elt, gc, nunits);
+ for (i = 0; i < nunits; ++i)
+ CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, sc);
+
+ if (CONSTANT_CLASS_P (sc))
+ return build_vector_from_ctor (vectype, v);
+ else
+ return build_constructor (vectype, v);
+}
+
/* Return a new CONSTRUCTOR node whose type is TYPE and whose values
are in the VEC pointed to by VALS. */
tree
/* Do not waste bytes provided by padding of struct tree_string. */
length = len + offsetof (struct tree_string, str) + 1;
-#ifdef GATHER_STATISTICS
- tree_node_counts[(int) c_kind]++;
- tree_node_sizes[(int) c_kind] += length;
-#endif
+ record_node_allocation_statistics (STRING_CST, length);
s = ggc_alloc_tree_node (length);
- memset (s, 0, sizeof (struct tree_common));
+ memset (s, 0, sizeof (struct tree_typed));
TREE_SET_CODE (s, STRING_CST);
TREE_CONSTANT (s) = 1;
TREE_STRING_LENGTH (s) = len;
case VECTOR_TYPE:
{
- tree scalar, cst;
- int i;
+ tree scalar = build_one_cst (TREE_TYPE (type));
- scalar = build_one_cst (TREE_TYPE (type));
-
- /* Create 'vect_cst_ = {cst,cst,...,cst}' */
- cst = NULL_TREE;
- for (i = TYPE_VECTOR_SUBPARTS (type); --i >= 0; )
- cst = tree_cons (NULL_TREE, scalar, cst);
-
- return build_vector (type, cst);
+ return build_vector_from_val (type, scalar);
}
case COMPLEX_TYPE:
return build_complex (type,
build_one_cst (TREE_TYPE (type)),
- fold_convert (TREE_TYPE (type), integer_zero_node));
+ build_zero_cst (TREE_TYPE (type)));
default:
gcc_unreachable ();
}
}
+/* Build 0 constant of type TYPE. This is used by constructor folding
+ and thus the constant should be represented in memory by
+ zero(es). */
+
+tree
+build_zero_cst (tree type)
+{
+ switch (TREE_CODE (type))
+ {
+ case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE:
+ case POINTER_TYPE: case REFERENCE_TYPE:
+ case OFFSET_TYPE:
+ return build_int_cst (type, 0);
+
+ case REAL_TYPE:
+ return build_real (type, dconst0);
+
+ case FIXED_POINT_TYPE:
+ return build_fixed (type, FCONST0 (TYPE_MODE (type)));
+
+ case VECTOR_TYPE:
+ {
+ tree scalar = build_zero_cst (TREE_TYPE (type));
+
+ return build_vector_from_val (type, scalar);
+ }
+
+ case COMPLEX_TYPE:
+ {
+ tree zero = build_zero_cst (TREE_TYPE (type));
+
+ return build_complex (type, zero, zero);
+ }
+
+ default:
+ if (!AGGREGATE_TYPE_P (type))
+ return fold_convert (type, integer_zero_node);
+ return build_constructor (type, NULL);
+ }
+}
+
+
/* Build a BINFO with LEN language slots. */
tree
size_t length = (offsetof (struct tree_binfo, base_binfos)
+ VEC_embedded_size (tree, base_binfos));
-#ifdef GATHER_STATISTICS
- tree_node_counts[(int) binfo_kind]++;
- tree_node_sizes[(int) binfo_kind] += length;
-#endif
+ record_node_allocation_statistics (TREE_BINFO, length);
t = ggc_alloc_zone_tree_node_stat (&tree_zone, length PASS_MEM_STAT);
return t;
}
+/* Create a CASE_LABEL_EXPR tree node and return it. */
+
+tree
+build_case_label (tree low_value, tree high_value, tree label_decl)
+{
+ tree t = make_node (CASE_LABEL_EXPR);
+
+ TREE_TYPE (t) = void_type_node;
+ SET_EXPR_LOCATION (t, DECL_SOURCE_LOCATION (label_decl));
+
+ CASE_LOW (t) = low_value;
+ CASE_HIGH (t) = high_value;
+ CASE_LABEL (t) = label_decl;
+ CASE_CHAIN (t) = NULL_TREE;
+
+ return t;
+}
/* Build a newly constructed TREE_VEC node of length LEN. */
tree t;
int length = (len - 1) * sizeof (tree) + sizeof (struct tree_vec);
-#ifdef GATHER_STATISTICS
- tree_node_counts[(int) vec_kind]++;
- tree_node_sizes[(int) vec_kind] += length;
-#endif
+ record_node_allocation_statistics (TREE_VEC, length);
t = ggc_alloc_zone_cleared_tree_node_stat (&tree_zone, length PASS_MEM_STAT);
if (!uns)
return 0;
- /* Note that using TYPE_PRECISION here is wrong. We care about the
- actual bits, not the (arbitrary) range of the type. */
- prec = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (expr)));
+ prec = TYPE_PRECISION (TREE_TYPE (expr));
if (prec >= HOST_BITS_PER_WIDE_INT)
{
HOST_WIDE_INT high_value;
PASS_MEM_STAT);
memset (node, 0, sizeof (struct tree_common));
-#ifdef GATHER_STATISTICS
- tree_node_counts[(int) x_kind]++;
- tree_node_sizes[(int) x_kind] += sizeof (struct tree_list);
-#endif
+ record_node_allocation_statistics (TREE_LIST, sizeof (struct tree_list));
TREE_SET_CODE (node, TREE_LIST);
TREE_CHAIN (node) = chain;
min = TYPE_MIN_VALUE (index_type);
max = TYPE_MAX_VALUE (index_type);
+ /* TYPE_MAX_VALUE may not be set if the array has unknown length. */
+ if (!max)
+ return error_mark_node;
+
return (integer_zerop (min)
? max
: fold_build2 (MINUS_EXPR, TREE_TYPE (max), max, min));
case BIT_FIELD_REF:
return NULL;
- case MISALIGNED_INDIRECT_REF:
case INDIRECT_REF:
return TREE_CONSTANT (TREE_OPERAND (arg, 0)) ? arg : NULL;
return true;
case VAR_DECL:
- if (((TREE_STATIC (op) || DECL_EXTERNAL (op))
- && !DECL_DLLIMPORT_P (op))
+ if ((TREE_STATIC (op) || DECL_EXTERNAL (op))
|| DECL_THREAD_LOCAL_P (op)
|| DECL_CONTEXT (op) == current_function_decl
|| decl_function_context (op) == current_function_decl)
TREE_READONLY (t) = read_only;
}
\f
-/* Return 1 if EXP contains a PLACEHOLDER_EXPR; i.e., if it represents a size
- or offset that depends on a field within a record. */
+/* Return true if EXP contains a PLACEHOLDER_EXPR, i.e. if it represents a
+ size or offset that depends on a field within a record. */
bool
contains_placeholder_p (const_tree exp)
return 0;
}
-/* Return true if any part of the computation of TYPE involves a
- PLACEHOLDER_EXPR. This includes size, bounds, qualifiers
- (for QUAL_UNION_TYPE) and field positions. */
+/* Return true if any part of the structure of TYPE involves a PLACEHOLDER_EXPR
+ directly. This includes size, bounds, qualifiers (for QUAL_UNION_TYPE) and
+ field positions. */
static bool
type_contains_placeholder_1 (const_tree type)
the case of arrays) type involves a placeholder, this type does. */
if (CONTAINS_PLACEHOLDER_P (TYPE_SIZE (type))
|| CONTAINS_PLACEHOLDER_P (TYPE_SIZE_UNIT (type))
- || (TREE_TYPE (type) != 0
+ || (!POINTER_TYPE_P (type)
+ && TREE_TYPE (type)
&& type_contains_placeholder_p (TREE_TYPE (type))))
return true;
|| CONTAINS_PLACEHOLDER_P (TYPE_MAX_VALUE (type)));
case ARRAY_TYPE:
- /* We're already checked the component type (TREE_TYPE), so just check
- the index type. */
+ /* We have already checked the component type above, so just check the
+ domain type. */
return type_contains_placeholder_p (TYPE_DOMAIN (type));
case RECORD_TYPE:
}
}
+/* Wrapper around above function used to cache its result. */
+
bool
type_contains_placeholder_p (tree type)
{
}
TREE_READONLY (new_tree) |= TREE_READONLY (exp);
+
+ if (code == INDIRECT_REF || code == ARRAY_REF || code == ARRAY_RANGE_REF)
+ TREE_THIS_NOTRAP (new_tree) |= TREE_THIS_NOTRAP (exp);
+
return new_tree;
}
}
TREE_READONLY (new_tree) |= TREE_READONLY (exp);
+
+ if (code == INDIRECT_REF || code == ARRAY_REF || code == ARRAY_RANGE_REF)
+ TREE_THIS_NOTRAP (new_tree) |= TREE_THIS_NOTRAP (exp);
+
return new_tree;
}
\f
build1_stat (enum tree_code code, tree type, tree node MEM_STAT_DECL)
{
int length = sizeof (struct tree_exp);
-#ifdef GATHER_STATISTICS
- tree_node_kind kind;
-#endif
tree t;
-#ifdef GATHER_STATISTICS
- switch (TREE_CODE_CLASS (code))
- {
- case tcc_statement: /* an expression with side effects */
- kind = s_kind;
- break;
- case tcc_reference: /* a reference */
- kind = r_kind;
- break;
- default:
- kind = e_kind;
- break;
- }
-
- tree_node_counts[(int) kind]++;
- tree_node_sizes[(int) kind] += length;
-#endif
+ record_node_allocation_statistics (code, length);
gcc_assert (TREE_CODE_LENGTH (code) == 1);
TREE_READONLY (t) = 0;
break;
- case MISALIGNED_INDIRECT_REF:
case INDIRECT_REF:
/* Whether a dereference is readonly has nothing to do with whether
its operand is readonly. */
double_int
mem_ref_offset (const_tree t)
{
- tree toff = TREE_CODE (t) == MEM_REF ? TREE_OPERAND (t, 1) : TMR_OFFSET (t);
+ tree toff = TREE_OPERAND (t, 1);
return double_int_sext (tree_to_double_int (toff),
TYPE_PRECISION (TREE_TYPE (toff)));
}
return TREE_TYPE (TREE_OPERAND (base, 1));
else if (TREE_CODE (base) == TARGET_MEM_REF)
return TREE_TYPE (TMR_OFFSET (base));
- else if (TREE_CODE (base) == MISALIGNED_INDIRECT_REF)
- return NULL_TREE;
else
return build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (base)));
}
+/* Return an invariant ADDR_EXPR of type TYPE taking the address of BASE
+ offsetted by OFFSET units. */
+
+tree
+build_invariant_address (tree type, tree base, HOST_WIDE_INT offset)
+{
+ tree ref = fold_build2 (MEM_REF, TREE_TYPE (type),
+ build_fold_addr_expr (base),
+ build_int_cst (ptr_type_node, offset));
+ tree addr = build1 (ADDR_EXPR, type, ref);
+ recompute_tree_invariant_for_addr_expr (addr);
+ return addr;
+}
+
/* Similar except don't specify the TREE_TYPE
and leave the TREE_SIDE_EFFECTS as 0.
It is permissible for arguments to be null,
return decl;
}
+VEC(tree,gc) *all_translation_units;
+
+/* Builds a new translation-unit decl with name NAME, queues it in the
+ global list of translation-unit decls and returns it. */
+
+tree
+build_translation_unit_decl (tree name)
+{
+ tree tu = build_decl (UNKNOWN_LOCATION, TRANSLATION_UNIT_DECL,
+ name, NULL_TREE);
+ TRANSLATION_UNIT_LANGUAGE (tu) = lang_hooks.name;
+ VEC_safe_push (tree, gc, all_translation_units, tu);
+ return tu;
+}
+
\f
/* BLOCK nodes are used to represent the structure of binding contours
and declarations, once those contours have been exited and their contents
its canonical type, we will need to use structural equality
checks for this type. */
if (TYPE_STRUCTURAL_EQUALITY_P (ttype)
- || !targetm.comp_type_attributes (ntype, ttype))
+ || !comp_type_attributes (ntype, ttype))
SET_TYPE_STRUCTURAL_EQUALITY (ntype);
else if (TYPE_CANONICAL (ntype) == ntype)
TYPE_CANONICAL (ntype) = TYPE_CANONICAL (ttype);
return ttype;
}
+/* Compare two attributes for their value identity. Return true if the
+ attribute values are known to be equal; otherwise return false.
+*/
+
+static bool
+attribute_value_equal (const_tree attr1, const_tree attr2)
+{
+ if (TREE_VALUE (attr1) == TREE_VALUE (attr2))
+ return true;
+
+ if (TREE_VALUE (attr1) != NULL_TREE
+ && TREE_CODE (TREE_VALUE (attr1)) == TREE_LIST
+ && TREE_VALUE (attr2) != NULL
+ && TREE_CODE (TREE_VALUE (attr2)) == TREE_LIST)
+ return (simple_cst_list_equal (TREE_VALUE (attr1),
+ TREE_VALUE (attr2)) == 1);
+
+ return (simple_cst_equal (TREE_VALUE (attr1), TREE_VALUE (attr2)) == 1);
+}
+
+/* Return 0 if the attributes for two types are incompatible, 1 if they
+ are compatible, and 2 if they are nearly compatible (which causes a
+ warning to be generated). */
+int
+comp_type_attributes (const_tree type1, const_tree type2)
+{
+ const_tree a1 = TYPE_ATTRIBUTES (type1);
+ const_tree a2 = TYPE_ATTRIBUTES (type2);
+ const_tree a;
+
+ if (a1 == a2)
+ return 1;
+ for (a = a1; a != NULL_TREE; a = TREE_CHAIN (a))
+ {
+ const struct attribute_spec *as;
+ const_tree attr;
+
+ as = lookup_attribute_spec (TREE_PURPOSE (a));
+ if (!as || as->affects_type_identity == false)
+ continue;
+
+ attr = lookup_attribute (as->name, CONST_CAST_TREE (a2));
+ if (!attr || !attribute_value_equal (a, attr))
+ break;
+ }
+ if (!a)
+ {
+ for (a = a2; a != NULL_TREE; a = TREE_CHAIN (a))
+ {
+ const struct attribute_spec *as;
+
+ as = lookup_attribute_spec (TREE_PURPOSE (a));
+ if (!as || as->affects_type_identity == false)
+ continue;
+
+ if (!lookup_attribute (as->name, CONST_CAST_TREE (a1)))
+ break;
+ /* We don't need to compare trees again, as we did this
+ already in first loop. */
+ }
+ /* All types - affecting identity - are equal, so
+ there is no need to call target hook for comparison. */
+ if (!a)
+ return 1;
+ }
+ /* As some type combinations - like default calling-convention - might
+ be compatible, we have to call the target hook to get the final result. */
+ return targetm.comp_type_attributes (type1, type2);
+}
/* Return a type like TTYPE except that its TYPE_ATTRIBUTE
is ATTRIBUTE.
}
-/* Remove all the non-variable decls from BLOCK. LOCALS is the set of
- variables in DECL_STRUCT_FUNCTION (FN)->local_decls. Every decl
- in BLOCK that is not in LOCALS is removed. */
-
-static void
-free_lang_data_in_block (tree fn, tree block, struct pointer_set_t *locals)
-{
- tree *tp, t;
-
- tp = &BLOCK_VARS (block);
- while (*tp)
- {
- if (!pointer_set_contains (locals, *tp))
- *tp = TREE_CHAIN (*tp);
- else
- tp = &TREE_CHAIN (*tp);
- }
-
- for (t = BLOCK_SUBBLOCKS (block); t; t = BLOCK_CHAIN (t))
- free_lang_data_in_block (fn, t, locals);
-}
-
-
/* Reset all language specific information still present in symbol
DECL. */
TREE_LANG_FLAG_5 (decl) = 0;
TREE_LANG_FLAG_6 (decl) = 0;
- /* Identifiers need not have a type. */
- if (DECL_NAME (decl))
- TREE_TYPE (DECL_NAME (decl)) = NULL_TREE;
-
- /* Ignore any intervening types, because we are going to clear their
- TYPE_CONTEXT fields. */
- if (TREE_CODE (decl) != FIELD_DECL
- && TREE_CODE (decl) != FUNCTION_DECL)
- DECL_CONTEXT (decl) = decl_function_context (decl);
-
- if (DECL_CONTEXT (decl)
- && TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL)
- DECL_CONTEXT (decl) = NULL_TREE;
-
- if (TREE_CODE (decl) == VAR_DECL)
- {
- tree context = DECL_CONTEXT (decl);
-
- if (context)
- {
- enum tree_code code = TREE_CODE (context);
- if (code == FUNCTION_DECL && DECL_ABSTRACT (context))
- {
- /* Do not clear the decl context here, that will promote
- all vars to global ones. */
- DECL_INITIAL (decl) = NULL_TREE;
- }
-
- if (TREE_STATIC (decl))
- DECL_CONTEXT (decl) = NULL_TREE;
- }
- }
-
free_lang_data_in_one_sizepos (&DECL_SIZE (decl));
free_lang_data_in_one_sizepos (&DECL_SIZE_UNIT (decl));
if (TREE_CODE (decl) == FIELD_DECL)
if (gimple_has_body_p (decl))
{
tree t;
- unsigned ix;
- struct pointer_set_t *locals;
/* If DECL has a gimple body, then the context for its
arguments must be DECL. Otherwise, it doesn't really
the PARM_DECL will be used in the function's body). */
for (t = DECL_ARGUMENTS (decl); t; t = TREE_CHAIN (t))
DECL_CONTEXT (t) = decl;
-
- /* Collect all the symbols declared in DECL. */
- locals = pointer_set_create ();
- FOR_EACH_LOCAL_DECL (DECL_STRUCT_FUNCTION (decl), ix, t)
- {
- pointer_set_insert (locals, t);
-
- /* All the local symbols should have DECL as their
- context. */
- DECL_CONTEXT (t) = decl;
- }
-
- /* Get rid of any decl not in local_decls. */
- free_lang_data_in_block (decl, DECL_INITIAL (decl), locals);
-
- pointer_set_destroy (locals);
}
/* DECL_SAVED_TREE holds the GENERIC representation for DECL.
At this point, it is not needed anymore. */
DECL_SAVED_TREE (decl) = NULL_TREE;
+
+ /* Clear the abstract origin if it refers to a method. Otherwise
+ dwarf2out.c will ICE as we clear TYPE_METHODS and thus the
+ origin will not be output correctly. */
+ if (DECL_ABSTRACT_ORIGIN (decl)
+ && DECL_CONTEXT (DECL_ABSTRACT_ORIGIN (decl))
+ && RECORD_OR_UNION_TYPE_P
+ (DECL_CONTEXT (DECL_ABSTRACT_ORIGIN (decl))))
+ DECL_ABSTRACT_ORIGIN (decl) = NULL_TREE;
+
+ /* Sometimes the C++ frontend doesn't manage to transform a temporary
+ DECL_VINDEX referring to itself into a vtable slot number as it
+ should. Happens with functions that are copied and then forgotten
+ about. Just clear it, it won't matter anymore. */
+ if (DECL_VINDEX (decl) && !host_integerp (DECL_VINDEX (decl), 0))
+ DECL_VINDEX (decl) = NULL_TREE;
}
else if (TREE_CODE (decl) == VAR_DECL)
{
- tree expr = DECL_DEBUG_EXPR (decl);
- if (expr
- && TREE_CODE (expr) == VAR_DECL
- && !TREE_STATIC (expr) && !DECL_EXTERNAL (expr))
- SET_DECL_DEBUG_EXPR (decl, NULL_TREE);
-
- if (DECL_EXTERNAL (decl)
- && (!TREE_STATIC (decl) || !TREE_READONLY (decl)))
+ if ((DECL_EXTERNAL (decl)
+ && (!TREE_STATIC (decl) || !TREE_READONLY (decl)))
+ || (decl_function_context (decl) && !TREE_STATIC (decl)))
DECL_INITIAL (decl) = NULL_TREE;
}
else if (TREE_CODE (decl) == TYPE_DECL)
- {
- DECL_INITIAL (decl) = NULL_TREE;
-
- /* DECL_CONTEXT is overloaded as DECL_FIELD_CONTEXT for
- FIELD_DECLs, which should be preserved. Otherwise,
- we shouldn't be concerned with source-level lexical
- nesting beyond this point. */
- DECL_CONTEXT (decl) = NULL_TREE;
+ DECL_INITIAL (decl) = NULL_TREE;
+ else if (TREE_CODE (decl) == TRANSLATION_UNIT_DECL
+ && DECL_INITIAL (decl)
+ && TREE_CODE (DECL_INITIAL (decl)) == BLOCK)
+ {
+ /* Strip builtins from the translation-unit BLOCK. We still have
+ targets without builtin_decl support and also builtins are
+ shared nodes and thus we can't use TREE_CHAIN in multiple
+ lists. */
+ tree *nextp = &BLOCK_VARS (DECL_INITIAL (decl));
+ while (*nextp)
+ {
+ tree var = *nextp;
+ if (TREE_CODE (var) == FUNCTION_DECL
+ && DECL_BUILT_IN (var))
+ *nextp = TREE_CHAIN (var);
+ else
+ nextp = &TREE_CHAIN (var);
+ }
}
}
fld_worklist_push (BLOCK_ABSTRACT_ORIGIN (t), fld);
}
- fld_worklist_push (TREE_TYPE (t), fld);
+ if (TREE_CODE (t) != IDENTIFIER_NODE
+ && CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_TYPED))
+ fld_worklist_push (TREE_TYPE (t), fld);
return NULL_TREE;
}
find_decls_types (p->decl, &fld);
/* Find decls and types in every varpool symbol. */
- for (v = varpool_nodes_queue; v; v = v->next_needed)
+ for (v = varpool_nodes; v; v = v->next)
find_decls_types_in_var (v, &fld);
/* Set the assembler name on every decl found. We need to do this
/* Create gimple variants for common types. */
ptrdiff_type_node = integer_type_node;
fileptr_type_node = ptr_type_node;
- if (TREE_CODE (boolean_type_node) != BOOLEAN_TYPE
- || (TYPE_MODE (boolean_type_node)
- != mode_for_size (BOOL_TYPE_SIZE, MODE_INT, 0))
- || TYPE_PRECISION (boolean_type_node) != 1
- || !TYPE_UNSIGNED (boolean_type_node))
- {
- boolean_type_node = make_unsigned_type (BOOL_TYPE_SIZE);
- TREE_SET_CODE (boolean_type_node, BOOLEAN_TYPE);
- TYPE_MAX_VALUE (boolean_type_node) = build_int_cst (boolean_type_node, 1);
- TYPE_PRECISION (boolean_type_node) = 1;
- boolean_false_node = TYPE_MIN_VALUE (boolean_type_node);
- boolean_true_node = TYPE_MAX_VALUE (boolean_type_node);
- }
-
- /* Unify char_type_node with its properly signed variant. */
- if (TYPE_UNSIGNED (char_type_node))
- unsigned_char_type_node = char_type_node;
- else
- signed_char_type_node = char_type_node;
/* Reset some langhooks. Do not reset types_compatible_p, it may
still be used indirectly via the get_alias_set langhook. */
lang_hooks.callgraph.analyze_expr = NULL;
lang_hooks.dwarf_name = lhd_dwarf_name;
lang_hooks.decl_printable_name = gimple_decl_printable_name;
- lang_hooks.set_decl_assembler_name = lhd_set_decl_assembler_name;
+ /* We do not want the default decl_assembler_name implementation,
+ rather if we have fixed everything we want a wrapper around it
+ asserting that all non-local symbols already got their assembler
+ name and only produce assembler names for local symbols. Or rather
+ make sure we never call decl_assembler_name on local symbols and
+ devise a separate, middle-end private scheme for it. */
/* Reset diagnostic machinery. */
diagnostic_starter (global_dc) = default_tree_diagnostic_starter;
}
};
-/* Return nonzero if IDENT is a valid name for attribute ATTR,
- or zero if not.
-
- We try both `text' and `__text__', ATTR may be either one. */
-/* ??? It might be a reasonable simplification to require ATTR to be only
- `text'. One might then also require attribute lists to be stored in
- their canonicalized form. */
-
-static int
-is_attribute_with_length_p (const char *attr, int attr_len, const_tree ident)
+/* The backbone of is_attribute_p(). ATTR_LEN is the string length of
+ ATTR_NAME. Also used internally by remove_attribute(). */
+bool
+private_is_attribute_p (const char *attr_name, size_t attr_len, const_tree ident)
{
- int ident_len;
- const char *p;
-
- if (TREE_CODE (ident) != IDENTIFIER_NODE)
- return 0;
-
- p = IDENTIFIER_POINTER (ident);
- ident_len = IDENTIFIER_LENGTH (ident);
-
- if (ident_len == attr_len
- && strcmp (attr, p) == 0)
- return 1;
+ size_t ident_len = IDENTIFIER_LENGTH (ident);
- /* If ATTR is `__text__', IDENT must be `text'; and vice versa. */
- if (attr[0] == '_')
+ if (ident_len == attr_len)
{
- gcc_assert (attr[1] == '_');
- gcc_assert (attr[attr_len - 2] == '_');
- gcc_assert (attr[attr_len - 1] == '_');
- if (ident_len == attr_len - 4
- && strncmp (attr + 2, p, attr_len - 4) == 0)
- return 1;
+ if (strcmp (attr_name, IDENTIFIER_POINTER (ident)) == 0)
+ return true;
}
- else
+ else if (ident_len == attr_len + 4)
{
- if (ident_len == attr_len + 4
- && p[0] == '_' && p[1] == '_'
+ /* There is the possibility that ATTR is 'text' and IDENT is
+ '__text__'. */
+ const char *p = IDENTIFIER_POINTER (ident);
+ if (p[0] == '_' && p[1] == '_'
&& p[ident_len - 2] == '_' && p[ident_len - 1] == '_'
- && strncmp (attr, p + 2, attr_len) == 0)
- return 1;
+ && strncmp (attr_name, p + 2, attr_len) == 0)
+ return true;
}
- return 0;
+ return false;
}
-/* Return nonzero if IDENT is a valid name for attribute ATTR,
- or zero if not.
-
- We try both `text' and `__text__', ATTR may be either one. */
-
-int
-is_attribute_p (const char *attr, const_tree ident)
+/* The backbone of lookup_attribute(). ATTR_LEN is the string length
+ of ATTR_NAME, and LIST is not NULL_TREE. */
+tree
+private_lookup_attribute (const char *attr_name, size_t attr_len, tree list)
{
- return is_attribute_with_length_p (attr, strlen (attr), ident);
-}
+ while (list)
+ {
+ size_t ident_len = IDENTIFIER_LENGTH (TREE_PURPOSE (list));
-/* Given an attribute name and a list of attributes, return a pointer to the
- attribute's list element if the attribute is part of the list, or NULL_TREE
- if not found. If the attribute appears more than once, this only
- returns the first occurrence; the TREE_CHAIN of the return value should
- be passed back in if further occurrences are wanted. */
+ if (ident_len == attr_len)
+ {
+ if (strcmp (attr_name, IDENTIFIER_POINTER (TREE_PURPOSE (list))) == 0)
+ break;
+ }
+ /* TODO: If we made sure that attributes were stored in the
+ canonical form without '__...__' (ie, as in 'text' as opposed
+ to '__text__') then we could avoid the following case. */
+ else if (ident_len == attr_len + 4)
+ {
+ const char *p = IDENTIFIER_POINTER (TREE_PURPOSE (list));
+ if (p[0] == '_' && p[1] == '_'
+ && p[ident_len - 2] == '_' && p[ident_len - 1] == '_'
+ && strncmp (attr_name, p + 2, attr_len) == 0)
+ break;
+ }
+ list = TREE_CHAIN (list);
+ }
-tree
-lookup_attribute (const char *attr_name, tree list)
+ return list;
+}
+
+/* A variant of lookup_attribute() that can be used with an identifier
+ as the first argument, and where the identifier can be either
+ 'text' or '__text__'.
+
+ Given an attribute ATTR_IDENTIFIER, and a list of attributes LIST,
+ return a pointer to the attribute's list element if the attribute
+ is part of the list, or NULL_TREE if not found. If the attribute
+ appears more than once, this only returns the first occurrence; the
+ TREE_CHAIN of the return value should be passed back in if further
+ occurrences are wanted. ATTR_IDENTIFIER must be an identifier but
+ can be in the form 'text' or '__text__'. */
+static tree
+lookup_ident_attribute (tree attr_identifier, tree list)
{
- tree l;
- size_t attr_len = strlen (attr_name);
+ gcc_checking_assert (TREE_CODE (attr_identifier) == IDENTIFIER_NODE);
- for (l = list; l; l = TREE_CHAIN (l))
+ while (list)
{
- gcc_assert (TREE_CODE (TREE_PURPOSE (l)) == IDENTIFIER_NODE);
- if (is_attribute_with_length_p (attr_name, attr_len, TREE_PURPOSE (l)))
- return l;
+ gcc_checking_assert (TREE_CODE (TREE_PURPOSE (list)) == IDENTIFIER_NODE);
+
+ /* Identifiers can be compared directly for equality. */
+ if (attr_identifier == TREE_PURPOSE (list))
+ break;
+
+ /* If they are not equal, they may still be one in the form
+ 'text' while the other one is in the form '__text__'. TODO:
+ If we were storing attributes in normalized 'text' form, then
+ this could all go away and we could take full advantage of
+ the fact that we're comparing identifiers. :-) */
+ {
+ size_t attr_len = IDENTIFIER_LENGTH (attr_identifier);
+ size_t ident_len = IDENTIFIER_LENGTH (TREE_PURPOSE (list));
+
+ if (ident_len == attr_len + 4)
+ {
+ const char *p = IDENTIFIER_POINTER (TREE_PURPOSE (list));
+ const char *q = IDENTIFIER_POINTER (attr_identifier);
+ if (p[0] == '_' && p[1] == '_'
+ && p[ident_len - 2] == '_' && p[ident_len - 1] == '_'
+ && strncmp (q, p + 2, attr_len) == 0)
+ break;
+ }
+ else if (ident_len + 4 == attr_len)
+ {
+ const char *p = IDENTIFIER_POINTER (TREE_PURPOSE (list));
+ const char *q = IDENTIFIER_POINTER (attr_identifier);
+ if (q[0] == '_' && q[1] == '_'
+ && q[attr_len - 2] == '_' && q[attr_len - 1] == '_'
+ && strncmp (q + 2, p, ident_len) == 0)
+ break;
+ }
+ }
+ list = TREE_CHAIN (list);
}
- return NULL_TREE;
+
+ return list;
}
/* Remove any instances of attribute ATTR_NAME in LIST and return the
tree *p;
size_t attr_len = strlen (attr_name);
+ gcc_checking_assert (attr_name[0] != '_');
+
for (p = &list; *p; )
{
tree l = *p;
- gcc_assert (TREE_CODE (TREE_PURPOSE (l)) == IDENTIFIER_NODE);
- if (is_attribute_with_length_p (attr_name, attr_len, TREE_PURPOSE (l)))
+ /* TODO: If we were storing attributes in normalized form, here
+ we could use a simple strcmp(). */
+ if (private_is_attribute_p (attr_name, attr_len, TREE_PURPOSE (l)))
*p = TREE_CHAIN (l);
else
p = &TREE_CHAIN (l);
for (; a2 != 0; a2 = TREE_CHAIN (a2))
{
tree a;
- for (a = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
- attributes);
- a != NULL_TREE;
- a = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
- TREE_CHAIN (a)))
- {
- if (TREE_VALUE (a) != NULL
- && TREE_CODE (TREE_VALUE (a)) == TREE_LIST
- && TREE_VALUE (a2) != NULL
- && TREE_CODE (TREE_VALUE (a2)) == TREE_LIST)
- {
- if (simple_cst_list_equal (TREE_VALUE (a),
- TREE_VALUE (a2)) == 1)
- break;
- }
- else if (simple_cst_equal (TREE_VALUE (a),
- TREE_VALUE (a2)) == 1)
- break;
- }
+ for (a = lookup_ident_attribute (TREE_PURPOSE (a2), attributes);
+ a != NULL_TREE && !attribute_value_equal (a, a2);
+ a = lookup_ident_attribute (TREE_PURPOSE (a2), TREE_CHAIN (a)))
+ ;
if (a == NULL_TREE)
{
a1 = copy_node (a2);
a = merge_attributes (DECL_ATTRIBUTES (old), DECL_ATTRIBUTES (new_tree));
if (delete_dllimport_p)
- {
- tree prev, t;
- const size_t attr_len = strlen ("dllimport");
-
- /* Scan the list for dllimport and delete it. */
- for (prev = NULL_TREE, t = a; t; prev = t, t = TREE_CHAIN (t))
- {
- if (is_attribute_with_length_p ("dllimport", attr_len,
- TREE_PURPOSE (t)))
- {
- if (prev == NULL_TREE)
- a = TREE_CHAIN (a);
- else
- TREE_CHAIN (prev) = TREE_CHAIN (t);
- break;
- }
- }
- }
+ a = remove_attribute ("dllimport", a);
return a;
}
DECL_DLLIMPORT_P (node) = 1;
}
else if (TREE_CODE (node) == FUNCTION_DECL
- && DECL_DECLARED_INLINE_P (node))
+ && DECL_DECLARED_INLINE_P (node)
+ && flag_keep_inline_dllexport)
/* An exported function, even if inline, must be emitted. */
DECL_EXTERNAL (node) = 0;
&& TYPE_NAME (cand) == TYPE_NAME (base)
/* Apparently this is needed for Objective-C. */
&& TYPE_CONTEXT (cand) == TYPE_CONTEXT (base)
+ /* Check alignment. */
+ && TYPE_ALIGN (cand) == TYPE_ALIGN (base)
+ && attribute_list_equal (TYPE_ATTRIBUTES (cand),
+ TYPE_ATTRIBUTES (base)));
+}
+
+/* Returns true iff CAND is equivalent to BASE with ALIGN. */
+
+static bool
+check_aligned_type (const_tree cand, const_tree base, unsigned int align)
+{
+ return (TYPE_QUALS (cand) == TYPE_QUALS (base)
+ && TYPE_NAME (cand) == TYPE_NAME (base)
+ /* Apparently this is needed for Objective-C. */
+ && TYPE_CONTEXT (cand) == TYPE_CONTEXT (base)
+ /* Check alignment. */
+ && TYPE_ALIGN (cand) == align
&& attribute_list_equal (TYPE_ATTRIBUTES (cand),
TYPE_ATTRIBUTES (base)));
}
return t;
}
+/* Create a variant of type T with alignment ALIGN. */
+
+tree
+build_aligned_type (tree type, unsigned int align)
+{
+ tree t;
+
+ if (TYPE_PACKED (type)
+ || TYPE_ALIGN (type) == align)
+ return type;
+
+ for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
+ if (check_aligned_type (t, type, align))
+ return t;
+
+ t = build_variant_type_copy (type);
+ TYPE_ALIGN (t) = align;
+
+ return t;
+}
+
/* Create a new distinct copy of TYPE. The new type is made its own
MAIN_VARIANT. If TYPE requires structural equality checks, the
resulting type requires structural equality checks; otherwise, its
struct tree_priority_map *h;
gcc_assert (VAR_OR_FUNCTION_DECL_P (decl));
+ if (priority == DEFAULT_INIT_PRIORITY)
+ return;
h = decl_priority_info (decl);
h->init = priority;
}
struct tree_priority_map *h;
gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
+ if (priority == DEFAULT_INIT_PRIORITY)
+ return;
h = decl_priority_info (decl);
h->fini = priority;
}
*(struct tree_decl_map **) loc = h;
}
+/* Lookup a vector of debug arguments for FROM, and return it if we
+ find one. */
+
+VEC(tree, gc) **
+decl_debug_args_lookup (tree from)
+{
+ struct tree_vec_map *h, in;
+
+ if (!DECL_HAS_DEBUG_ARGS_P (from))
+ return NULL;
+ gcc_checking_assert (debug_args_for_decl != NULL);
+ in.base.from = from;
+ h = (struct tree_vec_map *)
+ htab_find_with_hash (debug_args_for_decl, &in, DECL_UID (from));
+ if (h)
+ return &h->to;
+ return NULL;
+}
+
+/* Insert a mapping FROM->empty vector of debug arguments in the value
+ expression hashtable. */
+
+VEC(tree, gc) **
+decl_debug_args_insert (tree from)
+{
+ struct tree_vec_map *h;
+ void **loc;
+
+ if (DECL_HAS_DEBUG_ARGS_P (from))
+ return decl_debug_args_lookup (from);
+ if (debug_args_for_decl == NULL)
+ debug_args_for_decl = htab_create_ggc (64, tree_vec_map_hash,
+ tree_vec_map_eq, 0);
+ h = ggc_alloc_tree_vec_map ();
+ h->base.from = from;
+ h->to = NULL;
+ loc = htab_find_slot_with_hash (debug_args_for_decl, h, DECL_UID (from),
+ INSERT);
+ *(struct tree_vec_map **) loc = h;
+ DECL_HAS_DEBUG_ARGS_P (from) = 1;
+ return &h->to;
+}
+
/* Hashing of types so that we don't make duplicates.
The entry point is `type_hash_canon'. */
|| 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)
|| (TREE_CODE (a->type) != COMPLEX_TYPE
&& TYPE_NAME (a->type) != TYPE_NAME (b->type)))
return 0;
+ /* Be careful about comparing arrays before and after the element type
+ has been completed; don't compare TYPE_ALIGN unless both types are
+ complete. */
+ if (COMPLETE_TYPE_P (a->type) && COMPLETE_TYPE_P (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:
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)))));
-
+ if (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)))))
+ break;
+ return 0;
case ARRAY_TYPE:
return TYPE_DOMAIN (a->type) == TYPE_DOMAIN (b->type);
being passed. */
gcc_assert (TYPE_MAIN_VARIANT (type) == type);
- if (!lang_hooks.types.hash_types)
- return type;
-
/* See if the type is in the hash table already. If so, return it.
Otherwise, add the type. */
t1 = type_hash_lookup (hashcode, type);
if (t1 != 0)
{
#ifdef GATHER_STATISTICS
+ tree_code_counts[(int) TREE_CODE (type)]--;
tree_node_counts[(int) t_kind]--;
- tree_node_sizes[(int) t_kind] -= sizeof (struct tree_type);
+ tree_node_sizes[(int) t_kind] -= sizeof (struct tree_type_non_common);
#endif
return t1;
}
int
attribute_list_equal (const_tree l1, const_tree l2)
{
+ if (l1 == l2)
+ return 1;
+
return attribute_list_contained (l1, l2)
&& attribute_list_contained (l2, l1);
}
t1 != 0 && t2 != 0
&& TREE_PURPOSE (t1) == TREE_PURPOSE (t2)
&& TREE_VALUE (t1) == TREE_VALUE (t2);
- t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2));
+ t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
+ ;
/* Maybe the lists are equal. */
if (t1 == 0 && t2 == 0)
/* This CONST_CAST is okay because lookup_attribute does not
modify its argument and the return value is assigned to a
const_tree. */
- for (attr = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (t2)),
- CONST_CAST_TREE(l1));
- attr != NULL_TREE;
- attr = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (t2)),
- TREE_CHAIN (attr)))
- {
- if (TREE_VALUE (t2) != NULL
- && TREE_CODE (TREE_VALUE (t2)) == TREE_LIST
- && TREE_VALUE (attr) != NULL
- && TREE_CODE (TREE_VALUE (attr)) == TREE_LIST)
- {
- if (simple_cst_list_equal (TREE_VALUE (t2),
- TREE_VALUE (attr)) == 1)
- break;
- }
- else if (simple_cst_equal (TREE_VALUE (t2), TREE_VALUE (attr)) == 1)
- break;
- }
+ for (attr = lookup_ident_attribute (TREE_PURPOSE (t2), CONST_CAST_TREE(l1));
+ attr != NULL_TREE && !attribute_value_equal (t2, attr);
+ attr = lookup_ident_attribute (TREE_PURPOSE (t2), TREE_CHAIN (attr)))
+ ;
- if (attr == 0)
+ if (attr == NULL_TREE)
return 0;
}
}
return val;
}
+ case MEM_REF:
+ {
+ /* The type of the second operand is relevant, except for
+ its top-level qualifiers. */
+ tree type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (t, 1)));
+
+ val = iterative_hash_object (TYPE_HASH (type), val);
+
+ /* We could use the standard hash computation from this point
+ on. */
+ val = iterative_hash_object (code, val);
+ val = iterative_hash_expr (TREE_OPERAND (t, 1), val);
+ val = iterative_hash_expr (TREE_OPERAND (t, 0), val);
+ return val;
+ }
case FUNCTION_DECL:
/* When referring to a built-in FUNCTION_DECL, use the __builtin__ form.
Otherwise nodes that compare equal according to operand_equal_p might
}
}
-/* Create a type of integers to be the TYPE_DOMAIN of an ARRAY_TYPE.
- MAXVAL should be the maximum value in the domain
- (one less than the length of the array).
-
- The maximum value that MAXVAL can have is INT_MAX for a HOST_WIDE_INT.
- We don't enforce this limit, that is up to caller (e.g. language front end).
- The limit exists because the result is a signed type and we don't handle
- sizes that use more than one HOST_WIDE_INT. */
-
-tree
-build_index_type (tree maxval)
-{
- tree itype = make_node (INTEGER_TYPE);
-
- TREE_TYPE (itype) = sizetype;
- TYPE_PRECISION (itype) = TYPE_PRECISION (sizetype);
- TYPE_MIN_VALUE (itype) = size_zero_node;
- TYPE_MAX_VALUE (itype) = fold_convert (sizetype, maxval);
- SET_TYPE_MODE (itype, TYPE_MODE (sizetype));
- TYPE_SIZE (itype) = TYPE_SIZE (sizetype);
- TYPE_SIZE_UNIT (itype) = TYPE_SIZE_UNIT (sizetype);
- TYPE_ALIGN (itype) = TYPE_ALIGN (sizetype);
- TYPE_USER_ALIGN (itype) = TYPE_USER_ALIGN (sizetype);
-
- if (host_integerp (maxval, 1))
- return type_hash_canon (tree_low_cst (maxval, 1), itype);
- else
- {
- /* Since we cannot hash this type, we need to compare it using
- structural equality checks. */
- SET_TYPE_STRUCTURAL_EQUALITY (itype);
- return itype;
- }
-}
-
#define MAX_INT_CACHED_PREC \
(HOST_BITS_PER_WIDE_INT > 64 ? HOST_BITS_PER_WIDE_INT : 64)
static GTY(()) tree nonstandard_integer_type_cache[2 * MAX_INT_CACHED_PREC + 2];
ret = itype;
if (host_integerp (TYPE_MAX_VALUE (itype), 1))
ret = type_hash_canon (tree_low_cst (TYPE_MAX_VALUE (itype), 1), itype);
- if (precision <= MAX_INT_CACHED_PREC && lang_hooks.types.hash_types)
+ if (precision <= MAX_INT_CACHED_PREC)
nonstandard_integer_type_cache[precision + unsignedp] = ret;
return ret;
}
-/* Create a range of some discrete type TYPE (an INTEGER_TYPE,
- ENUMERAL_TYPE or BOOLEAN_TYPE), with low bound LOWVAL and
- high bound HIGHVAL. If TYPE is NULL, sizetype is used. */
+/* Create a range of some discrete type TYPE (an INTEGER_TYPE, ENUMERAL_TYPE
+ or BOOLEAN_TYPE) with low bound LOWVAL and high bound HIGHVAL. If SHARED
+ is true, reuse such a type that has already been constructed. */
-tree
-build_range_type (tree type, tree lowval, tree highval)
+static tree
+build_range_type_1 (tree type, tree lowval, tree highval, bool shared)
{
tree itype = make_node (INTEGER_TYPE);
+ hashval_t hashcode = 0;
TREE_TYPE (itype) = type;
- if (type == NULL_TREE)
- type = sizetype;
TYPE_MIN_VALUE (itype) = fold_convert (type, lowval);
TYPE_MAX_VALUE (itype) = highval ? fold_convert (type, highval) : NULL;
TYPE_ALIGN (itype) = TYPE_ALIGN (type);
TYPE_USER_ALIGN (itype) = TYPE_USER_ALIGN (type);
- if (host_integerp (lowval, 0) && highval != 0 && host_integerp (highval, 0))
- return type_hash_canon (tree_low_cst (highval, 0)
- - tree_low_cst (lowval, 0),
- itype);
- else
+ if (!shared)
return itype;
+
+ if ((TYPE_MIN_VALUE (itype)
+ && TREE_CODE (TYPE_MIN_VALUE (itype)) != INTEGER_CST)
+ || (TYPE_MAX_VALUE (itype)
+ && TREE_CODE (TYPE_MAX_VALUE (itype)) != INTEGER_CST))
+ {
+ /* Since we cannot reliably merge this type, we need to compare it using
+ structural equality checks. */
+ SET_TYPE_STRUCTURAL_EQUALITY (itype);
+ return itype;
+ }
+
+ hashcode = iterative_hash_expr (TYPE_MIN_VALUE (itype), hashcode);
+ hashcode = iterative_hash_expr (TYPE_MAX_VALUE (itype), hashcode);
+ hashcode = iterative_hash_hashval_t (TYPE_HASH (type), hashcode);
+ itype = type_hash_canon (hashcode, itype);
+
+ return itype;
+}
+
+/* Wrapper around build_range_type_1 with SHARED set to true. */
+
+tree
+build_range_type (tree type, tree lowval, tree highval)
+{
+ return build_range_type_1 (type, lowval, highval, true);
+}
+
+/* Wrapper around build_range_type_1 with SHARED set to false. */
+
+tree
+build_nonshared_range_type (tree type, tree lowval, tree highval)
+{
+ return build_range_type_1 (type, lowval, highval, false);
+}
+
+/* Create a type of integers to be the TYPE_DOMAIN of an ARRAY_TYPE.
+ MAXVAL should be the maximum value in the domain
+ (one less than the length of the array).
+
+ The maximum value that MAXVAL can have is INT_MAX for a HOST_WIDE_INT.
+ We don't enforce this limit, that is up to caller (e.g. language front end).
+ The limit exists because the result is a signed type and we don't handle
+ sizes that use more than one HOST_WIDE_INT. */
+
+tree
+build_index_type (tree maxval)
+{
+ return build_range_type (sizetype, size_zero_node, maxval);
}
/* Return true if the debug information for TYPE, a subtype, should be emitted
return true;
}
-/* Just like build_index_type, but takes lowval and highval instead
- of just highval (maxval). */
-
-tree
-build_index_2_type (tree lowval, tree highval)
-{
- return build_range_type (sizetype, lowval, highval);
-}
-
/* Construct, lay out and return the type of arrays of elements with ELT_TYPE
and number of elements specified by the range of values of INDEX_TYPE.
- If such a type has already been constructed, reuse it. */
+ If SHARED is true, reuse such a type that has already been constructed. */
-tree
-build_array_type (tree elt_type, tree index_type)
+static tree
+build_array_type_1 (tree elt_type, tree index_type, bool shared)
{
tree t;
- hashval_t hashcode = 0;
if (TREE_CODE (elt_type) == FUNCTION_TYPE)
{
if (TYPE_STRUCTURAL_EQUALITY_P (t))
return t;
- hashcode = iterative_hash_object (TYPE_HASH (elt_type), hashcode);
- if (index_type)
- hashcode = iterative_hash_object (TYPE_HASH (index_type), hashcode);
- t = type_hash_canon (hashcode, t);
+ if (shared)
+ {
+ hashval_t hashcode = iterative_hash_object (TYPE_HASH (elt_type), 0);
+ if (index_type)
+ hashcode = iterative_hash_object (TYPE_HASH (index_type), hashcode);
+ t = type_hash_canon (hashcode, t);
+ }
if (TYPE_CANONICAL (t) == t)
{
else if (TYPE_CANONICAL (elt_type) != elt_type
|| (index_type && TYPE_CANONICAL (index_type) != index_type))
TYPE_CANONICAL (t)
- = build_array_type (TYPE_CANONICAL (elt_type),
- index_type ? TYPE_CANONICAL (index_type) : NULL);
+ = build_array_type_1 (TYPE_CANONICAL (elt_type),
+ index_type
+ ? TYPE_CANONICAL (index_type) : NULL_TREE,
+ shared);
}
return t;
}
+/* Wrapper around build_array_type_1 with SHARED set to true. */
+
+tree
+build_array_type (tree elt_type, tree index_type)
+{
+ return build_array_type_1 (elt_type, index_type, true);
+}
+
+/* Wrapper around build_array_type_1 with SHARED set to false. */
+
+tree
+build_nonshared_array_type (tree elt_type, tree index_type)
+{
+ return build_array_type_1 (elt_type, index_type, false);
+}
+
+/* Return a representation of ELT_TYPE[NELTS], using indices of type
+ sizetype. */
+
+tree
+build_array_type_nelts (tree elt_type, unsigned HOST_WIDE_INT nelts)
+{
+ return build_array_type (elt_type, build_index_type (size_int (nelts - 1)));
+}
+
/* Recursively examines the array elements of TYPE, until a non-array
element type is found. */
return args;
}
+/* Build a function type. RETURN_TYPE is the type returned by the
+ function; VAARGS indicates whether the function takes varargs. The
+ function takes N named arguments, the types of which are provided in
+ ARG_TYPES. */
+
+static tree
+build_function_type_array_1 (bool vaargs, tree return_type, int n,
+ tree *arg_types)
+{
+ int i;
+ tree t = vaargs ? NULL_TREE : void_list_node;
+
+ for (i = n - 1; i >= 0; i--)
+ t = tree_cons (NULL_TREE, arg_types[i], t);
+
+ return build_function_type (return_type, t);
+}
+
+/* Build a function type. RETURN_TYPE is the type returned by the
+ function. The function takes N named arguments, the types of which
+ are provided in ARG_TYPES. */
+
+tree
+build_function_type_array (tree return_type, int n, tree *arg_types)
+{
+ return build_function_type_array_1 (false, return_type, n, arg_types);
+}
+
+/* Build a variable argument function type. RETURN_TYPE is the type
+ returned by the function. The function takes N named arguments, the
+ types of which are provided in ARG_TYPES. */
+
+tree
+build_varargs_function_type_array (tree return_type, int n, tree *arg_types)
+{
+ return build_function_type_array_1 (true, return_type, n, arg_types);
+}
+
/* Build a METHOD_TYPE for a member of BASETYPE. The RETTYPE (a TYPE)
and ARGTYPES (a TREE_LIST) are the return type and arguments types
for the method. An implicit additional parameter (of type
fprintf (stderr, "---------------------------------------\n");
fprintf (stderr, "%-20s %7d %10d\n", "Total", total_nodes, total_bytes);
fprintf (stderr, "---------------------------------------\n");
+ fprintf (stderr, "Code Nodes\n");
+ fprintf (stderr, "----------------------------\n");
+ for (i = 0; i < (int) MAX_TREE_CODES; i++)
+ fprintf (stderr, "%-20s %7d\n", tree_code_name[i], tree_code_counts[i]);
+ fprintf (stderr, "----------------------------\n");
ssanames_print_statistics ();
phinodes_print_statistics ();
#else
\f
#define FILE_FUNCTION_FORMAT "_GLOBAL__%s_%s"
-/* Generate a crc32 of a string. */
+/* Generate a crc32 of a byte. */
unsigned
-crc32_string (unsigned chksum, const char *string)
+crc32_byte (unsigned chksum, char byte)
{
- do
- {
- unsigned value = *string << 24;
+ unsigned value = (unsigned) byte << 24;
unsigned ix;
for (ix = 8; ix--; value <<= 1)
chksum <<= 1;
chksum ^= feedback;
}
+ return chksum;
+}
+
+
+/* Generate a crc32 of a string. */
+
+unsigned
+crc32_string (unsigned chksum, const char *string)
+{
+ do
+ {
+ chksum = crc32_byte (chksum, *string);
}
while (*string++);
return chksum;
*p = '_';
}
-/* Generate a name for a special-purpose function function.
+/* Generate a name for a special-purpose function.
The generated name may need to be unique across the whole link.
+ Changes to this function may also require corresponding changes to
+ xstrdup_mask_random.
TYPE is some string to identify the purpose of this function to the
linker or collect2; it must start with an uppercase letter,
one of:
p = q = ASTRDUP (first_global_object_name);
/* If the target is handling the constructors/destructors, they
will be local to this file and the name is only necessary for
- debugging purposes. */
- else if ((type[0] == 'I' || type[0] == 'D') && targetm.have_ctors_dtors)
+ debugging purposes.
+ We also assign sub_I and sub_D sufixes to constructors called from
+ the global static constructors. These are always local. */
+ else if (((type[0] == 'I' || type[0] == 'D') && targetm.have_ctors_dtors)
+ || (strncmp (type, "sub_", 4) == 0
+ && (type[4] == 'I' || type[4] == 'D')))
{
const char *file = main_input_filename;
if (! file)
file = input_filename;
/* Just use the file's basename, because the full pathname
might be quite long. */
- p = strrchr (file, '/');
- if (p)
- p++;
- else
- p = file;
- p = q = ASTRDUP (p);
+ p = q = ASTRDUP (lbasename (file));
}
else
{
layout_type (t);
- {
- tree index = build_int_cst (NULL_TREE, nunits - 1);
- tree array = build_array_type (TYPE_MAIN_VARIANT (innertype),
- build_index_type (index));
- tree rt = make_node (RECORD_TYPE);
-
- TYPE_FIELDS (rt) = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
- get_identifier ("f"), array);
- DECL_CONTEXT (TYPE_FIELDS (rt)) = rt;
- layout_type (rt);
- TYPE_DEBUG_REPRESENTATION_TYPE (t) = rt;
- /* In dwarfout.c, type lookup uses TYPE_UID numbers. We want to output
- the representation type, and we want to find that die when looking up
- the vector type. This is most easily achieved by making the TYPE_UID
- numbers equal. */
- TYPE_UID (rt) = TYPE_UID (t);
- }
-
hashcode = iterative_hash_host_wide_int (VECTOR_TYPE, hashcode);
hashcode = iterative_hash_host_wide_int (nunits, hashcode);
hashcode = iterative_hash_host_wide_int (mode, hashcode);
}
/* 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. */
+ of C datatypes. SIGNED_CHAR specifies whether char is signed,
+ SHORT_DOUBLE specifies whether double should be of the same precision
+ as float. */
void
-build_common_tree_nodes (bool signed_char)
+build_common_tree_nodes (bool signed_char, bool short_double)
{
error_mark_node = make_node (ERROR_MARK);
TREE_TYPE (error_mark_node) = error_mark_node;
int128_unsigned_type_node = make_unsigned_type (128);
}
#endif
+
/* Define a boolean type. This type only represents boolean values but
may be larger than char depending on the value of BOOL_TYPE_SIZE.
Front ends which want to override this size (i.e. Java) can redefine
TYPE_MAX_VALUE (boolean_type_node) = build_int_cst (boolean_type_node, 1);
TYPE_PRECISION (boolean_type_node) = 1;
+ /* Define what type to use for size_t. */
+ if (strcmp (SIZE_TYPE, "unsigned int") == 0)
+ size_type_node = unsigned_type_node;
+ else if (strcmp (SIZE_TYPE, "long unsigned int") == 0)
+ size_type_node = long_unsigned_type_node;
+ else if (strcmp (SIZE_TYPE, "long long unsigned int") == 0)
+ size_type_node = long_long_unsigned_type_node;
+ else if (strcmp (SIZE_TYPE, "short unsigned int") == 0)
+ size_type_node = short_unsigned_type_node;
+ else
+ gcc_unreachable ();
+
/* 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);
access_public_node = get_identifier ("public");
access_protected_node = get_identifier ("protected");
access_private_node = get_identifier ("private");
-}
-/* Call this function after calling build_common_tree_nodes and set_sizetype.
- It will create several other common tree nodes. */
-
-void
-build_common_tree_nodes_2 (int short_double)
-{
/* Define these next since types below may used them. */
integer_zero_node = build_int_cst (integer_type_node, 0);
integer_one_node = build_int_cst (integer_type_node, 1);
TREE_NOTHROW (decl) = 1;
if (ecf_flags & ECF_MALLOC)
DECL_IS_MALLOC (decl) = 1;
+ if (ecf_flags & ECF_LEAF)
+ DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("leaf"),
+ NULL, DECL_ATTRIBUTES (decl));
built_in_decls[code] = decl;
implicit_built_in_decls[code] = decl;
if (built_in_decls[BUILT_IN_MEMCPY] == NULL)
local_define_builtin ("__builtin_memcpy", ftype, BUILT_IN_MEMCPY,
- "memcpy", ECF_NOTHROW);
+ "memcpy", ECF_NOTHROW | ECF_LEAF);
if (built_in_decls[BUILT_IN_MEMMOVE] == NULL)
local_define_builtin ("__builtin_memmove", ftype, BUILT_IN_MEMMOVE,
- "memmove", ECF_NOTHROW);
+ "memmove", ECF_NOTHROW | ECF_LEAF);
}
if (built_in_decls[BUILT_IN_MEMCMP] == NULL)
const_ptr_type_node, size_type_node,
NULL_TREE);
local_define_builtin ("__builtin_memcmp", ftype, BUILT_IN_MEMCMP,
- "memcmp", ECF_PURE | ECF_NOTHROW);
+ "memcmp", ECF_PURE | ECF_NOTHROW | ECF_LEAF);
}
if (built_in_decls[BUILT_IN_MEMSET] == NULL)
ptr_type_node, integer_type_node,
size_type_node, NULL_TREE);
local_define_builtin ("__builtin_memset", ftype, BUILT_IN_MEMSET,
- "memset", ECF_NOTHROW);
+ "memset", ECF_NOTHROW | ECF_LEAF);
}
if (built_in_decls[BUILT_IN_ALLOCA] == NULL)
ftype = build_function_type_list (ptr_type_node,
size_type_node, NULL_TREE);
local_define_builtin ("__builtin_alloca", ftype, BUILT_IN_ALLOCA,
- "alloca", ECF_MALLOC | ECF_NOTHROW);
+ "alloca", ECF_MALLOC | ECF_NOTHROW | ECF_LEAF);
}
/* If we're checking the stack, `alloca' can throw. */
ptr_type_node, NULL_TREE);
local_define_builtin ("__builtin_init_trampoline", ftype,
BUILT_IN_INIT_TRAMPOLINE,
- "__builtin_init_trampoline", ECF_NOTHROW);
+ "__builtin_init_trampoline", ECF_NOTHROW | ECF_LEAF);
ftype = build_function_type_list (ptr_type_node, ptr_type_node, NULL_TREE);
local_define_builtin ("__builtin_adjust_trampoline", ftype,
ftype = build_function_type_list (ptr_type_node, NULL_TREE);
local_define_builtin ("__builtin_stack_save", ftype, BUILT_IN_STACK_SAVE,
- "__builtin_stack_save", ECF_NOTHROW);
+ "__builtin_stack_save", ECF_NOTHROW | ECF_LEAF);
ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
local_define_builtin ("__builtin_stack_restore", ftype,
BUILT_IN_STACK_RESTORE,
- "__builtin_stack_restore", ECF_NOTHROW);
-
- ftype = build_function_type_list (void_type_node, NULL_TREE);
- local_define_builtin ("__builtin_profile_func_enter", ftype,
- BUILT_IN_PROFILE_FUNC_ENTER, "profile_func_enter", 0);
- local_define_builtin ("__builtin_profile_func_exit", ftype,
- BUILT_IN_PROFILE_FUNC_EXIT, "profile_func_exit", 0);
+ "__builtin_stack_restore", ECF_NOTHROW | ECF_LEAF);
/* If there's a possibility that we might use the ARM EABI, build the
alternate __cxa_end_cleanup node used to resume from C++ and Java. */
ftype = build_function_type_list (void_type_node, NULL_TREE);
local_define_builtin ("__builtin_cxa_end_cleanup", ftype,
BUILT_IN_CXA_END_CLEANUP,
- "__cxa_end_cleanup", ECF_NORETURN);
+ "__cxa_end_cleanup", ECF_NORETURN | ECF_LEAF);
}
ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
local_define_builtin ("__builtin_unwind_resume", ftype,
BUILT_IN_UNWIND_RESUME,
- (USING_SJLJ_EXCEPTIONS
+ ((targetm_common.except_unwind_info (&global_options)
+ == UI_SJLJ)
? "_Unwind_SjLj_Resume" : "_Unwind_Resume"),
ECF_NORETURN);
+ if (built_in_decls[BUILT_IN_RETURN_ADDRESS] == NULL_TREE)
+ {
+ ftype = build_function_type_list (ptr_type_node, integer_type_node,
+ NULL_TREE);
+ local_define_builtin ("__builtin_return_address", ftype,
+ BUILT_IN_RETURN_ADDRESS,
+ "__builtin_return_address",
+ ECF_NOTHROW);
+ }
+
+ if (built_in_decls[BUILT_IN_PROFILE_FUNC_ENTER] == NULL_TREE
+ || built_in_decls[BUILT_IN_PROFILE_FUNC_EXIT] == NULL_TREE)
+ {
+ ftype = build_function_type_list (void_type_node, ptr_type_node,
+ ptr_type_node, NULL_TREE);
+ if (built_in_decls[BUILT_IN_PROFILE_FUNC_ENTER] == NULL_TREE)
+ local_define_builtin ("__cyg_profile_func_enter", ftype,
+ BUILT_IN_PROFILE_FUNC_ENTER,
+ "__cyg_profile_func_enter", 0);
+ if (built_in_decls[BUILT_IN_PROFILE_FUNC_EXIT] == NULL_TREE)
+ local_define_builtin ("__cyg_profile_func_exit", ftype,
+ BUILT_IN_PROFILE_FUNC_EXIT,
+ "__cyg_profile_func_exit", 0);
+ }
+
/* The exception object and filter values from the runtime. The argument
must be zero before exception lowering, i.e. from the front end. After
exception lowering, it will be the region number for the exception
ftype = build_function_type_list (ptr_type_node,
integer_type_node, NULL_TREE);
local_define_builtin ("__builtin_eh_pointer", ftype, BUILT_IN_EH_POINTER,
- "__builtin_eh_pointer", ECF_PURE | ECF_NOTHROW);
+ "__builtin_eh_pointer", ECF_PURE | ECF_NOTHROW | ECF_LEAF);
tmp = lang_hooks.types.type_for_mode (targetm.eh_return_filter_mode (), 0);
ftype = build_function_type_list (tmp, integer_type_node, NULL_TREE);
local_define_builtin ("__builtin_eh_filter", ftype, BUILT_IN_EH_FILTER,
- "__builtin_eh_filter", ECF_PURE | ECF_NOTHROW);
+ "__builtin_eh_filter", ECF_PURE | ECF_NOTHROW | ECF_LEAF);
ftype = build_function_type_list (void_type_node,
integer_type_node, integer_type_node,
const char *p;
enum built_in_function mcode, dcode;
tree type, inner_type;
+ const char *prefix = "__";
+
+ if (targetm.libfunc_gnu_prefix)
+ prefix = "__gnu_";
type = lang_hooks.types.type_for_mode ((enum machine_mode) mode, 0);
if (type == NULL)
*q = TOLOWER (*p);
*q = '\0';
- built_in_names[mcode] = concat ("__mul", mode_name_buf, "3", NULL);
+ built_in_names[mcode] = concat (prefix, "mul", mode_name_buf, "3",
+ NULL);
local_define_builtin (built_in_names[mcode], ftype, mcode,
- built_in_names[mcode], ECF_CONST | ECF_NOTHROW);
+ built_in_names[mcode],
+ ECF_CONST | ECF_NOTHROW | ECF_LEAF);
- built_in_names[dcode] = concat ("__div", mode_name_buf, "3", NULL);
+ built_in_names[dcode] = concat (prefix, "div", mode_name_buf, "3",
+ NULL);
local_define_builtin (built_in_names[dcode], ftype, dcode,
- built_in_names[dcode], ECF_CONST | ECF_NOTHROW);
+ built_in_names[dcode],
+ ECF_CONST | ECF_NOTHROW | ECF_LEAF);
}
}
}
length = omp_clause_num_ops[code];
size = (sizeof (struct tree_omp_clause) + (length - 1) * sizeof (tree));
+ record_node_allocation_statistics (OMP_CLAUSE, size);
+
t = ggc_alloc_tree_node (size);
memset (t, 0, size);
TREE_SET_CODE (t, OMP_CLAUSE);
OMP_CLAUSE_SET_CODE (t, code);
OMP_CLAUSE_LOCATION (t) = loc;
-#ifdef GATHER_STATISTICS
- tree_node_counts[(int) omp_clause_kind]++;
- tree_node_sizes[(int) omp_clause_kind] += size;
-#endif
-
return t;
}
gcc_assert (TREE_CODE_CLASS (code) == tcc_vl_exp);
gcc_assert (len >= 1);
-#ifdef GATHER_STATISTICS
- tree_node_counts[(int) e_kind]++;
- tree_node_sizes[(int) e_kind] += length;
-#endif
+ record_node_allocation_statistics (code, length);
t = ggc_alloc_zone_cleared_tree_node_stat (&tree_zone, length PASS_MEM_STAT);
return t;
}
+/* Helper function for build_call_* functions; build a CALL_EXPR with
+ indicated RETURN_TYPE, FN, and NARGS, but do not initialize any of
+ the argument slots. */
+
+static tree
+build_call_1 (tree return_type, tree fn, int nargs)
+{
+ tree t;
+
+ t = build_vl_exp (CALL_EXPR, nargs + 3);
+ TREE_TYPE (t) = return_type;
+ CALL_EXPR_FN (t) = fn;
+ CALL_EXPR_STATIC_CHAIN (t) = NULL;
+
+ return t;
+}
+
/* Build a CALL_EXPR of class tcc_vl_exp with the indicated RETURN_TYPE and
FN and a null static chain slot. NARGS is the number of call arguments
which are specified as "..." arguments. */
tree t;
int i;
- t = build_vl_exp (CALL_EXPR, nargs + 3);
- TREE_TYPE (t) = return_type;
- CALL_EXPR_FN (t) = fn;
- CALL_EXPR_STATIC_CHAIN (t) = NULL_TREE;
+ t = build_call_1 (return_type, fn, nargs);
for (i = 0; i < nargs; i++)
CALL_EXPR_ARG (t, i) = va_arg (args, tree);
process_call_operands (t);
tree t;
int i;
- t = build_vl_exp (CALL_EXPR, nargs + 3);
- TREE_TYPE (t) = return_type;
- CALL_EXPR_FN (t) = fn;
- CALL_EXPR_STATIC_CHAIN (t) = NULL_TREE;
+ t = build_call_1 (return_type, fn, nargs);
for (i = 0; i < nargs; i++)
CALL_EXPR_ARG (t, i) = args[i];
process_call_operands (t);
tree ret, t;
unsigned int ix;
- ret = build_vl_exp (CALL_EXPR, VEC_length (tree, args) + 3);
- TREE_TYPE (ret) = return_type;
- CALL_EXPR_FN (ret) = fn;
- CALL_EXPR_STATIC_CHAIN (ret) = NULL_TREE;
+ ret = build_call_1 (return_type, fn, VEC_length (tree, args));
FOR_EACH_VEC_ELT (tree, args, ix, t)
CALL_EXPR_ARG (ret, ix) = t;
process_call_operands (ret);
&& aggregate_value_p (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 (const_tree f1, const_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 (!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 and sign-extend it. */
HOST_WIDE_INT
tree
upper_bound_in_type (tree outer, tree inner)
{
- unsigned HOST_WIDE_INT lo, hi;
+ double_int high;
unsigned int det = 0;
unsigned oprec = TYPE_PRECISION (outer);
unsigned iprec = TYPE_PRECISION (inner);
/* Compute 2^^prec - 1. */
if (prec <= HOST_BITS_PER_WIDE_INT)
{
- hi = 0;
- lo = ((~(unsigned HOST_WIDE_INT) 0)
+ high.high = 0;
+ high.low = ((~(unsigned HOST_WIDE_INT) 0)
>> (HOST_BITS_PER_WIDE_INT - prec));
}
else
{
- hi = ((~(unsigned HOST_WIDE_INT) 0)
+ high.high = ((~(unsigned HOST_WIDE_INT) 0)
>> (2 * HOST_BITS_PER_WIDE_INT - prec));
- lo = ~(unsigned HOST_WIDE_INT) 0;
+ high.low = ~(unsigned HOST_WIDE_INT) 0;
}
- return build_int_cst_wide (outer, lo, hi);
+ return double_int_to_tree (outer, high);
}
/* Returns the smallest value obtainable by casting something in INNER type to
tree
lower_bound_in_type (tree outer, tree inner)
{
- unsigned HOST_WIDE_INT lo, hi;
+ double_int low;
unsigned oprec = TYPE_PRECISION (outer);
unsigned iprec = TYPE_PRECISION (inner);
contains all values of INNER type. In particular, both INNER
and OUTER types have zero in common. */
|| (oprec > iprec && TYPE_UNSIGNED (inner)))
- lo = hi = 0;
+ low.low = low.high = 0;
else
{
/* If we are widening a signed type to another signed type, we
if (prec <= HOST_BITS_PER_WIDE_INT)
{
- hi = ~(unsigned HOST_WIDE_INT) 0;
- lo = (~(unsigned HOST_WIDE_INT) 0) << (prec - 1);
+ low.high = ~(unsigned HOST_WIDE_INT) 0;
+ low.low = (~(unsigned HOST_WIDE_INT) 0) << (prec - 1);
}
else
{
- hi = ((~(unsigned HOST_WIDE_INT) 0)
+ low.high = ((~(unsigned HOST_WIDE_INT) 0)
<< (prec - HOST_BITS_PER_WIDE_INT - 1));
- lo = 0;
+ low.low = 0;
}
}
- return build_int_cst_wide (outer, lo, hi);
+ return double_int_to_tree (outer, low);
}
/* Return nonzero if two operands that are suitable for PHI nodes are
case OMP_CLAUSE_FIRSTPRIVATE:
case OMP_CLAUSE_COPYIN:
case OMP_CLAUSE_COPYPRIVATE:
+ case OMP_CLAUSE_FINAL:
case OMP_CLAUSE_IF:
case OMP_CLAUSE_NUM_THREADS:
case OMP_CLAUSE_SCHEDULE:
case OMP_CLAUSE_ORDERED:
case OMP_CLAUSE_DEFAULT:
case OMP_CLAUSE_UNTIED:
+ case OMP_CLAUSE_MERGEABLE:
WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
case OMP_CLAUSE_LASTPRIVATE:
if (result || !walk_subtrees)
return result;
- result = walk_type_fields (*type_p, func, data, pset, lh);
- if (result)
- return result;
+ /* But do not walk a pointed-to type since it may itself need to
+ be walked in the declaration case if it isn't anonymous. */
+ if (!POINTER_TYPE_P (*type_p))
+ {
+ result = walk_type_fields (*type_p, func, data, pset, lh);
+ if (result)
+ return result;
+ }
/* If this is a record type, also walk the fields. */
if (RECORD_OR_UNION_TYPE_P (*type_p))
/* Return true if TYPE has a variable argument list. */
bool
-stdarg_p (tree fntype)
+stdarg_p (const_tree fntype)
{
function_args_iterator args_iter;
tree n = NULL_TREE, t;
/* Use the cache of optimization nodes. */
- cl_optimization_save (TREE_OPTIMIZATION (cl_optimization_node));
+ cl_optimization_save (TREE_OPTIMIZATION (cl_optimization_node),
+ &global_options);
slot = htab_find_slot (cl_option_hash_table, cl_optimization_node, INSERT);
t = (tree) *slot;
/* Use the cache of optimization nodes. */
- cl_target_option_save (TREE_TARGET_OPTION (cl_target_option_node));
+ cl_target_option_save (TREE_TARGET_OPTION (cl_target_option_node),
+ &global_options);
slot = htab_find_slot (cl_option_hash_table, cl_target_option_node, INSERT);
t = (tree) *slot;
lhd_gcc_personality (void)
{
if (!gcc_eh_personality_decl)
- gcc_eh_personality_decl
- = build_personality_function (USING_SJLJ_EXCEPTIONS
- ? "__gcc_personality_sj0"
- : "__gcc_personality_v0");
-
+ gcc_eh_personality_decl = build_personality_function ("gcc");
return gcc_eh_personality_decl;
}
tree
get_binfo_at_offset (tree binfo, HOST_WIDE_INT offset, tree expected_type)
{
- tree type;
+ tree type = BINFO_TYPE (binfo);
- if (offset == 0)
- return binfo;
-
- type = TREE_TYPE (binfo);
- while (offset > 0)
+ while (true)
{
- tree base_binfo, found_binfo;
HOST_WIDE_INT pos, size;
tree fld;
int i;
- if (TREE_CODE (type) != RECORD_TYPE)
+ if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (expected_type))
+ return binfo;
+ if (offset < 0)
return NULL_TREE;
for (fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld))
if (pos <= offset && (pos + size) > offset)
break;
}
- if (!fld)
+ if (!fld || TREE_CODE (TREE_TYPE (fld)) != RECORD_TYPE)
return NULL_TREE;
- found_binfo = NULL_TREE;
- for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
- if (TREE_TYPE (base_binfo) == TREE_TYPE (fld))
- {
- found_binfo = base_binfo;
- break;
- }
-
- if (!found_binfo)
- return NULL_TREE;
+ if (!DECL_ARTIFICIAL (fld))
+ {
+ binfo = TYPE_BINFO (TREE_TYPE (fld));
+ if (!binfo)
+ return NULL_TREE;
+ }
+ /* Offset 0 indicates the primary base, whose vtable contents are
+ represented in the binfo for the derived class. */
+ else if (offset != 0)
+ {
+ tree base_binfo, found_binfo = NULL_TREE;
+ for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+ if (TREE_TYPE (base_binfo) == TREE_TYPE (fld))
+ {
+ found_binfo = base_binfo;
+ break;
+ }
+ if (!found_binfo)
+ return NULL_TREE;
+ binfo = found_binfo;
+ }
type = TREE_TYPE (fld);
- binfo = found_binfo;
offset -= pos;
}
- if (type != expected_type)
- return NULL_TREE;
- return binfo;
}
/* Returns true if X is a typedef decl. */
return is_typedef_decl (TYPE_NAME (type));
}
+/* Warn about a use of an identifier which was marked deprecated. */
+void
+warn_deprecated_use (tree node, tree attr)
+{
+ const char *msg;
+
+ if (node == 0 || !warn_deprecated_decl)
+ return;
+
+ if (!attr)
+ {
+ if (DECL_P (node))
+ attr = DECL_ATTRIBUTES (node);
+ else if (TYPE_P (node))
+ {
+ tree decl = TYPE_STUB_DECL (node);
+ if (decl)
+ attr = lookup_attribute ("deprecated",
+ TYPE_ATTRIBUTES (TREE_TYPE (decl)));
+ }
+ }
+
+ if (attr)
+ attr = lookup_attribute ("deprecated", attr);
+
+ if (attr)
+ msg = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)));
+ else
+ msg = NULL;
+
+ if (DECL_P (node))
+ {
+ expanded_location xloc = expand_location (DECL_SOURCE_LOCATION (node));
+ if (msg)
+ warning (OPT_Wdeprecated_declarations,
+ "%qD is deprecated (declared at %s:%d): %s",
+ node, xloc.file, xloc.line, msg);
+ else
+ warning (OPT_Wdeprecated_declarations,
+ "%qD is deprecated (declared at %s:%d)",
+ node, xloc.file, xloc.line);
+ }
+ else if (TYPE_P (node))
+ {
+ tree what = NULL_TREE;
+ tree decl = TYPE_STUB_DECL (node);
+
+ if (TYPE_NAME (node))
+ {
+ if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE)
+ what = TYPE_NAME (node);
+ else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL
+ && DECL_NAME (TYPE_NAME (node)))
+ what = DECL_NAME (TYPE_NAME (node));
+ }
+
+ if (decl)
+ {
+ expanded_location xloc
+ = expand_location (DECL_SOURCE_LOCATION (decl));
+ if (what)
+ {
+ if (msg)
+ warning (OPT_Wdeprecated_declarations,
+ "%qE is deprecated (declared at %s:%d): %s",
+ what, xloc.file, xloc.line, msg);
+ else
+ warning (OPT_Wdeprecated_declarations,
+ "%qE is deprecated (declared at %s:%d)", what,
+ xloc.file, xloc.line);
+ }
+ else
+ {
+ if (msg)
+ warning (OPT_Wdeprecated_declarations,
+ "type is deprecated (declared at %s:%d): %s",
+ xloc.file, xloc.line, msg);
+ else
+ warning (OPT_Wdeprecated_declarations,
+ "type is deprecated (declared at %s:%d)",
+ xloc.file, xloc.line);
+ }
+ }
+ else
+ {
+ if (what)
+ {
+ if (msg)
+ warning (OPT_Wdeprecated_declarations, "%qE is deprecated: %s",
+ what, msg);
+ else
+ warning (OPT_Wdeprecated_declarations, "%qE is deprecated", what);
+ }
+ else
+ {
+ if (msg)
+ warning (OPT_Wdeprecated_declarations, "type is deprecated: %s",
+ msg);
+ else
+ warning (OPT_Wdeprecated_declarations, "type is deprecated");
+ }
+ }
+ }
+}
+
#include "gt-tree.h"