/* 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
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
/* This file contains the low level primitives for operating on tree nodes,
including allocation, list operations, interning of identifiers,
#include "tree-flow.h"
#include "params.h"
#include "pointer-set.h"
+#include "fixed-value.h"
+
+/* Tree code classes. */
+
+#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
+#define END_OF_BASE_TREE_CODES tcc_exceptional,
+
+const enum tree_code_class tree_code_type[] = {
+#include "all-tree.def"
+};
+
+#undef DEFTREECODE
+#undef END_OF_BASE_TREE_CODES
+
+/* Table indexed by tree code giving number of expression
+ operands beyond the fixed part of the node structure.
+ Not used for types or decls. */
+
+#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH,
+#define END_OF_BASE_TREE_CODES 0,
+
+const unsigned char tree_code_length[] = {
+#include "all-tree.def"
+};
+
+#undef DEFTREECODE
+#undef END_OF_BASE_TREE_CODES
+
+/* Names of tree components.
+ Used for printing out the tree and error messages. */
+#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
+#define END_OF_BASE_TREE_CODES "@dummy",
+
+const char *const tree_code_name[] = {
+#include "all-tree.def"
+};
+
+#undef DEFTREECODE
+#undef END_OF_BASE_TREE_CODES
/* Each tree code class has an associated string representation.
These must correspond to the tree_code_class entries. */
"binary",
"statement",
"vl_exp",
- "expression",
- "gimple_stmt"
+ "expression"
};
/* obstack.[ch] explicitly declined to prototype this. */
"temp_tree_lists",
"vecs",
"binfos",
- "phi_nodes",
"ssa names",
"constructors",
"random kinds",
"lang_decl kinds",
"lang_type kinds",
"omp clauses",
- "gimple statements"
};
#endif /* GATHER_STATISTICS */
static GTY ((if_marked ("ggc_marked_p"), param_is (union tree_node)))
htab_t int_cst_hash_table;
+/* Hash table for optimization flags and target option flags. Use the same
+ hash table for both sets of options. Nodes for building the current
+ optimization and target option nodes. The assumption is most of the time
+ the options created will already be in the hash table, so we avoid
+ allocating and freeing up a node repeatably. */
+static GTY (()) tree cl_optimization_node;
+static GTY (()) tree cl_target_option_node;
+static GTY ((if_marked ("ggc_marked_p"), param_is (union tree_node)))
+ htab_t cl_option_hash_table;
+
/* General tree->tree mapping structure for use in hash tables. */
static hashval_t type_hash_hash (const void *);
static hashval_t int_cst_hash_hash (const void *);
static int int_cst_hash_eq (const void *, const void *);
+static hashval_t cl_option_hash_hash (const void *);
+static int cl_option_hash_eq (const void *, const void *);
static void print_type_hash_statistics (void);
static void print_debug_expr_statistics (void);
static void print_value_expr_statistics (void);
static int type_hash_marked_p (const void *);
-static unsigned int type_hash_list (tree, hashval_t);
-static unsigned int attribute_hash_list (tree, hashval_t);
+static unsigned int type_hash_list (const_tree, hashval_t);
+static unsigned int attribute_hash_list (const_tree, hashval_t);
tree global_trees[TI_MAX];
tree integer_types[itk_none];
1, /* OMP_CLAUSE_PRIVATE */
1, /* OMP_CLAUSE_SHARED */
1, /* OMP_CLAUSE_FIRSTPRIVATE */
- 1, /* OMP_CLAUSE_LASTPRIVATE */
+ 2, /* OMP_CLAUSE_LASTPRIVATE */
4, /* OMP_CLAUSE_REDUCTION */
1, /* OMP_CLAUSE_COPYIN */
1, /* OMP_CLAUSE_COPYPRIVATE */
1, /* OMP_CLAUSE_SCHEDULE */
0, /* OMP_CLAUSE_NOWAIT */
0, /* OMP_CLAUSE_ORDERED */
- 0 /* OMP_CLAUSE_DEFAULT */
+ 0, /* OMP_CLAUSE_DEFAULT */
+ 3, /* OMP_CLAUSE_COLLAPSE */
+ 0 /* OMP_CLAUSE_UNTIED */
};
const char * const omp_clause_code_name[] =
"schedule",
"nowait",
"ordered",
- "default"
+ "default",
+ "collapse",
+ "untied"
};
\f
/* Init tree.c. */
int_cst_node = make_node (INTEGER_CST);
+ cl_option_hash_table = htab_create_ggc (64, cl_option_hash_hash,
+ cl_option_hash_eq, NULL);
+
+ cl_optimization_node = make_node (OPTIMIZATION_NODE);
+ cl_target_option_node = make_node (TARGET_OPTION_NODE);
+
tree_contains_struct[FUNCTION_DECL][TS_DECL_NON_COMMON] = 1;
tree_contains_struct[TRANSLATION_UNIT_DECL][TS_DECL_NON_COMMON] = 1;
tree_contains_struct[TYPE_DECL][TS_DECL_NON_COMMON] = 1;
tree_contains_struct[TRANSLATION_UNIT_DECL][TS_DECL_MINIMAL] = 1;
tree_contains_struct[LABEL_DECL][TS_DECL_MINIMAL] = 1;
tree_contains_struct[FIELD_DECL][TS_DECL_MINIMAL] = 1;
- tree_contains_struct[STRUCT_FIELD_TAG][TS_DECL_MINIMAL] = 1;
tree_contains_struct[NAME_MEMORY_TAG][TS_DECL_MINIMAL] = 1;
tree_contains_struct[SYMBOL_MEMORY_TAG][TS_DECL_MINIMAL] = 1;
tree_contains_struct[MEMORY_PARTITION_TAG][TS_DECL_MINIMAL] = 1;
- tree_contains_struct[STRUCT_FIELD_TAG][TS_MEMORY_TAG] = 1;
tree_contains_struct[NAME_MEMORY_TAG][TS_MEMORY_TAG] = 1;
tree_contains_struct[SYMBOL_MEMORY_TAG][TS_MEMORY_TAG] = 1;
tree_contains_struct[MEMORY_PARTITION_TAG][TS_MEMORY_TAG] = 1;
- tree_contains_struct[STRUCT_FIELD_TAG][TS_STRUCT_FIELD_TAG] = 1;
tree_contains_struct[MEMORY_PARTITION_TAG][TS_MEMORY_PARTITION_TAG] = 1;
tree_contains_struct[VAR_DECL][TS_DECL_WITH_VIS] = 1;
/* Compare ASMNAME with the DECL_ASSEMBLER_NAME of DECL. */
bool
-decl_assembler_name_equal (tree decl, tree asmname)
+decl_assembler_name_equal (tree decl, const_tree asmname)
{
tree decl_asmname = DECL_ASSEMBLER_NAME (decl);
+ const char *decl_str;
+ const char *asmname_str;
+ bool test = false;
if (decl_asmname == asmname)
return true;
+ decl_str = IDENTIFIER_POINTER (decl_asmname);
+ asmname_str = IDENTIFIER_POINTER (asmname);
+
+
/* If the target assembler name was set by the user, things are trickier.
We have a leading '*' to begin with. After that, it's arguable what
is the correct thing to do with -fleading-underscore. Arguably, we've
historically been doing the wrong thing in assemble_alias by always
printing the leading underscore. Since we're not changing that, make
sure user_label_prefix follows the '*' before matching. */
- if (IDENTIFIER_POINTER (decl_asmname)[0] == '*')
+ if (decl_str[0] == '*')
+ {
+ size_t ulp_len = strlen (user_label_prefix);
+
+ decl_str ++;
+
+ if (ulp_len == 0)
+ test = true;
+ else if (strncmp (decl_str, user_label_prefix, ulp_len) == 0)
+ decl_str += ulp_len, test=true;
+ else
+ decl_str --;
+ }
+ if (asmname_str[0] == '*')
+ {
+ size_t ulp_len = strlen (user_label_prefix);
+
+ asmname_str ++;
+
+ if (ulp_len == 0)
+ test = true;
+ else if (strncmp (asmname_str, user_label_prefix, ulp_len) == 0)
+ asmname_str += ulp_len, test=true;
+ else
+ asmname_str --;
+ }
+
+ if (!test)
+ return false;
+ return strcmp (decl_str, asmname_str) == 0;
+}
+
+/* Hash asmnames ignoring the user specified marks. */
+
+hashval_t
+decl_assembler_name_hash (const_tree asmname)
+{
+ if (IDENTIFIER_POINTER (asmname)[0] == '*')
{
- const char *decl_str = IDENTIFIER_POINTER (decl_asmname) + 1;
+ const char *decl_str = IDENTIFIER_POINTER (asmname) + 1;
size_t ulp_len = strlen (user_label_prefix);
if (ulp_len == 0)
;
else if (strncmp (decl_str, user_label_prefix, ulp_len) == 0)
decl_str += ulp_len;
- else
- return false;
- return strcmp (decl_str, IDENTIFIER_POINTER (asmname)) == 0;
+ return htab_hash_string (decl_str);
}
- return false;
+ return htab_hash_string (IDENTIFIER_POINTER (asmname));
}
/* Compute the number of bytes occupied by a tree with code CODE.
This function cannot be used for nodes that have variable sizes,
- including TREE_VEC, PHI_NODE, STRING_CST, and CALL_EXPR. */
+ including TREE_VEC, STRING_CST, and CALL_EXPR. */
size_t
tree_code_size (enum tree_code code)
{
case NAME_MEMORY_TAG:
case SYMBOL_MEMORY_TAG:
return sizeof (struct tree_memory_tag);
- case STRUCT_FIELD_TAG:
- return sizeof (struct tree_struct_field_tag);
case MEMORY_PARTITION_TAG:
return sizeof (struct tree_memory_partition_tag);
default:
return (sizeof (struct tree_exp)
+ (TREE_CODE_LENGTH (code) - 1) * sizeof (tree));
- case tcc_gimple_stmt:
- return (sizeof (struct gimple_stmt)
- + (TREE_CODE_LENGTH (code) - 1) * sizeof (char *));
-
case tcc_constant: /* a constant */
switch (code)
{
case INTEGER_CST: return sizeof (struct tree_int_cst);
case REAL_CST: return sizeof (struct tree_real_cst);
+ case FIXED_CST: return sizeof (struct tree_fixed_cst);
case COMPLEX_CST: return sizeof (struct tree_complex);
case VECTOR_CST: return sizeof (struct tree_vector);
case STRING_CST: gcc_unreachable ();
case PLACEHOLDER_EXPR: return sizeof (struct tree_common);
case TREE_VEC:
- case OMP_CLAUSE:
- case PHI_NODE: gcc_unreachable ();
+ case OMP_CLAUSE: gcc_unreachable ();
case SSA_NAME: return sizeof (struct tree_ssa_name);
case STATEMENT_LIST: return sizeof (struct tree_statement_list);
case BLOCK: return sizeof (struct tree_block);
- case VALUE_HANDLE: return sizeof (struct tree_value_handle);
case CONSTRUCTOR: return sizeof (struct tree_constructor);
+ case OPTIMIZATION_NODE: return sizeof (struct tree_optimization_option);
+ case TARGET_OPTION_NODE: return sizeof (struct tree_target_option);
default:
return lang_hooks.tree_size (code);
/* Compute the number of bytes occupied by NODE. This routine only
looks at TREE_CODE, except for those nodes that have variable sizes. */
size_t
-tree_size (tree node)
+tree_size (const_tree node)
{
- enum tree_code code = TREE_CODE (node);
+ const enum tree_code code = TREE_CODE (node);
switch (code)
{
- case PHI_NODE:
- return (sizeof (struct tree_phi_node)
- + (PHI_ARG_CAPACITY (node) - 1) * sizeof (struct phi_arg_d));
-
case TREE_BINFO:
return (offsetof (struct tree_binfo, base_binfos)
+ VEC_embedded_size (tree, BINFO_N_BASE_BINFOS (node)));
/* 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 PHI_NODE,
- TREE_VEC or OMP_CLAUSE nodes, which is enforced by asserts in
- tree_code_size.
+ 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. */
kind = c_kind;
break;
- case tcc_gimple_stmt:
- kind = gimple_stmt_kind;
- break;
-
case tcc_exceptional: /* something random, like an identifier. */
switch (code)
{
kind = binfo_kind;
break;
- case PHI_NODE:
- kind = phi_kind;
- break;
-
case SSA_NAME:
kind = ssa_name_kind;
break;
#endif
if (code == IDENTIFIER_NODE)
- t = ggc_alloc_zone_pass_stat (length, &tree_id_zone);
+ t = (tree) ggc_alloc_zone_pass_stat (length, &tree_id_zone);
else
- t = ggc_alloc_zone_pass_stat (length, &tree_zone);
+ t = (tree) ggc_alloc_zone_pass_stat (length, &tree_zone);
memset (t, 0, length);
break;
case tcc_declaration:
- if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
- DECL_IN_SYSTEM_HEADER (t) = in_system_header;
if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
{
- if (code != FUNCTION_DECL)
+ if (code == FUNCTION_DECL)
+ {
+ DECL_ALIGN (t) = FUNCTION_BOUNDARY;
+ DECL_MODE (t) = FUNCTION_MODE;
+ }
+ else
DECL_ALIGN (t) = 1;
- DECL_USER_ALIGN (t) = 0;
/* We have not yet computed the alias set for this declaration. */
DECL_POINTER_ALIAS_SET (t) = -1;
}
case tcc_constant:
TREE_CONSTANT (t) = 1;
- TREE_INVARIANT (t) = 1;
break;
case tcc_expression:
}
break;
- case tcc_gimple_stmt:
- switch (code)
- {
- case GIMPLE_MODIFY_STMT:
- TREE_SIDE_EFFECTS (t) = 1;
- break;
-
- default:
- break;
- }
-
default:
/* Other classes need no special treatment. */
break;
gcc_assert (code != STATEMENT_LIST);
length = tree_size (node);
- t = ggc_alloc_zone_pass_stat (length, &tree_zone);
+ t = (tree) ggc_alloc_zone_pass_stat (length, &tree_zone);
memcpy (t, node, length);
- if (!GIMPLE_TUPLE_P (node))
- TREE_CHAIN (t) = 0;
+ TREE_CHAIN (t) = 0;
TREE_ASM_WRITTEN (t) = 0;
TREE_VISITED (t) = 0;
t->base.ann = 0;
static hashval_t
int_cst_hash_hash (const void *x)
{
- tree t = (tree) x;
+ const_tree const t = (const_tree) x;
return (TREE_INT_CST_HIGH (t) ^ TREE_INT_CST_LOW (t)
^ htab_hash_pointer (TREE_TYPE (t)));
static int
int_cst_hash_eq (const void *x, const void *y)
{
- tree xt = (tree) x;
- tree yt = (tree) y;
+ const_tree const xt = (const_tree) x;
+ const_tree const yt = (const_tree) y;
return (TREE_TYPE (xt) == TREE_TYPE (yt)
&& TREE_INT_CST_HIGH (xt) == TREE_INT_CST_HIGH (yt)
TREE_TYPE (int_cst_node) = type;
slot = htab_find_slot (int_cst_hash_table, int_cst_node, INSERT);
- t = *slot;
+ t = (tree) *slot;
if (!t)
{
/* Insert this one into the hash table. */
HOST_WIDE_INT without loss of precision. */
bool
-cst_and_fits_in_hwi (tree x)
+cst_and_fits_in_hwi (const_tree x)
{
if (TREE_CODE (x) != INTEGER_CST)
return false;
return t;
}
+/* Return a new FIXED_CST node whose type is TYPE and value is F. */
+
+tree
+build_fixed (tree type, FIXED_VALUE_TYPE f)
+{
+ tree v;
+ FIXED_VALUE_TYPE *fp;
+
+ v = make_node (FIXED_CST);
+ fp = GGC_NEW (FIXED_VALUE_TYPE);
+ memcpy (fp, &f, sizeof (FIXED_VALUE_TYPE));
+
+ TREE_TYPE (v) = type;
+ TREE_FIXED_CST_PTR (v) = fp;
+ return v;
+}
/* Return a new REAL_CST node whose type is TYPE and value is D. */
Consider doing it via real_convert now. */
v = make_node (REAL_CST);
- dp = ggc_alloc (sizeof (REAL_VALUE_TYPE));
+ dp = GGC_NEW (REAL_VALUE_TYPE);
memcpy (dp, &d, sizeof (REAL_VALUE_TYPE));
TREE_TYPE (v) = type;
and whose value is the integer value of the INTEGER_CST node I. */
REAL_VALUE_TYPE
-real_value_from_int_cst (tree type, tree i)
+real_value_from_int_cst (const_tree type, const_tree i)
{
REAL_VALUE_TYPE d;
representing the same value as a floating-point constant of type TYPE. */
tree
-build_real_from_int_cst (tree type, tree i)
+build_real_from_int_cst (tree type, const_tree i)
{
tree v;
int overflow = TREE_OVERFLOW (i);
memset (s, 0, sizeof (struct tree_common));
TREE_SET_CODE (s, STRING_CST);
TREE_CONSTANT (s) = 1;
- TREE_INVARIANT (s) = 1;
TREE_STRING_LENGTH (s) = len;
- memcpy ((char *) TREE_STRING_POINTER (s), str, len);
- ((char *) TREE_STRING_POINTER (s))[len] = '\0';
+ memcpy (s->string.str, str, len);
+ s->string.str[len] = '\0';
return s;
}
case REAL_TYPE:
return build_real (type, dconst1);
+ case FIXED_POINT_TYPE:
+ /* We can only generate 1 for accum types. */
+ gcc_assert (ALL_SCALAR_ACCUM_MODE_P (TYPE_MODE (type)));
+ return build_fixed (type, FCONST1(TYPE_MODE (type)));
+
case VECTOR_TYPE:
{
tree scalar, cst;
tree_node_sizes[(int) binfo_kind] += length;
#endif
- t = ggc_alloc_zone_pass_stat (length, &tree_zone);
+ t = (tree) ggc_alloc_zone_pass_stat (length, &tree_zone);
memset (t, 0, offsetof (struct tree_binfo, base_binfos));
tree_node_sizes[(int) vec_kind] += length;
#endif
- t = ggc_alloc_zone_pass_stat (length, &tree_zone);
+ t = (tree) ggc_alloc_zone_pass_stat (length, &tree_zone);
memset (t, 0, length);
of zero. */
int
-integer_zerop (tree expr)
+integer_zerop (const_tree expr)
{
STRIP_NOPS (expr);
complex constant. */
int
-integer_onep (tree expr)
+integer_onep (const_tree expr)
{
STRIP_NOPS (expr);
it contains. Likewise for the corresponding complex constant. */
int
-integer_all_onesp (tree expr)
+integer_all_onesp (const_tree expr)
{
int prec;
int uns;
one bit on). */
int
-integer_pow2p (tree expr)
+integer_pow2p (const_tree expr)
{
int prec;
HOST_WIDE_INT high, low;
complex constant other than zero. */
int
-integer_nonzerop (tree expr)
+integer_nonzerop (const_tree expr)
{
STRIP_NOPS (expr);
|| integer_nonzerop (TREE_IMAGPART (expr)))));
}
+/* Return 1 if EXPR is the fixed-point constant zero. */
+
+int
+fixed_zerop (const_tree expr)
+{
+ return (TREE_CODE (expr) == FIXED_CST
+ && double_int_zero_p (TREE_FIXED_CST (expr).data));
+}
+
/* Return the power of two represented by a tree node known to be a
power of two. */
int
-tree_log2 (tree expr)
+tree_log2 (const_tree expr)
{
int prec;
HOST_WIDE_INT high, low;
than or equal to EXPR. */
int
-tree_floor_log2 (tree expr)
+tree_floor_log2 (const_tree expr)
{
int prec;
HOST_WIDE_INT high, low;
/* Return 1 if EXPR is the real constant zero. */
int
-real_zerop (tree expr)
+real_zerop (const_tree expr)
{
STRIP_NOPS (expr);
/* Return 1 if EXPR is the real constant one in real or complex form. */
int
-real_onep (tree expr)
+real_onep (const_tree expr)
{
STRIP_NOPS (expr);
/* Return 1 if EXPR is the real constant two. */
int
-real_twop (tree expr)
+real_twop (const_tree expr)
{
STRIP_NOPS (expr);
/* Return 1 if EXPR is the real constant minus one. */
int
-real_minus_onep (tree expr)
+real_minus_onep (const_tree expr)
{
STRIP_NOPS (expr);
/* Nonzero if EXP is a constant or a cast of a constant. */
int
-really_constant_p (tree exp)
+really_constant_p (const_tree exp)
{
/* This is not quite the same as STRIP_NOPS. It does more. */
- while (TREE_CODE (exp) == NOP_EXPR
- || TREE_CODE (exp) == CONVERT_EXPR
+ while (CONVERT_EXPR_P (exp)
|| TREE_CODE (exp) == NON_LVALUE_EXPR)
exp = TREE_OPERAND (exp, 0);
return TREE_CONSTANT (exp);
Return 0 if ELEM is not in LIST. */
tree
-purpose_member (tree elem, tree list)
+purpose_member (const_tree elem, tree list)
{
while (list)
{
/* Return nonzero if ELEM is part of the chain CHAIN. */
int
-chain_member (tree elem, tree chain)
+chain_member (const_tree elem, const_tree chain)
{
while (chain)
{
This is the Lisp primitive `length'. */
int
-list_length (tree t)
+list_length (const_tree t)
{
- tree p = t;
+ const_tree p = t;
#ifdef ENABLE_TREE_CHECKING
- tree q = t;
+ const_tree q = t;
#endif
int len = 0;
/* Returns the number of FIELD_DECLs in TYPE. */
int
-fields_length (tree type)
+fields_length (const_tree type)
{
tree t = TYPE_FIELDS (type);
int count = 0;
{
tree node;
- node = ggc_alloc_zone_pass_stat (sizeof (struct tree_list), &tree_zone);
+ node = (tree) ggc_alloc_zone_pass_stat (sizeof (struct tree_list), &tree_zone);
memset (node, 0, sizeof (struct tree_common));
return node;
}
+/* Return the elements of a CONSTRUCTOR as a TREE_LIST. */
+
+tree
+ctor_to_list (tree ctor)
+{
+ tree list = NULL_TREE;
+ tree *p = &list;
+ unsigned ix;
+ tree purpose, val;
+
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), ix, purpose, val)
+ {
+ *p = build_tree_list (purpose, val);
+ p = &TREE_CHAIN (*p);
+ }
+
+ return list;
+}
\f
/* Return the size nominally occupied by an object of type TYPE
when it resides in memory. The value is measured in units of bytes,
make_unsigned_type). */
tree
-size_in_bytes (tree type)
+size_in_bytes (const_tree type)
{
tree t;
or return -1 if the size can vary or is larger than an integer. */
HOST_WIDE_INT
-int_size_in_bytes (tree type)
+int_size_in_bytes (const_tree type)
{
tree t;
or return -1 if the size can vary or is larger than an integer. */
HOST_WIDE_INT
-max_int_size_in_bytes (tree type)
+max_int_size_in_bytes (const_tree type)
{
HOST_WIDE_INT size = -1;
tree size_tree;
This is a tree of type bitsizetype. */
tree
-bit_position (tree field)
+bit_position (const_tree field)
{
return bit_from_pos (DECL_FIELD_OFFSET (field),
DECL_FIELD_BIT_OFFSET (field));
option of returning -1 like int_size_in_byte can. */
HOST_WIDE_INT
-int_bit_position (tree field)
+int_bit_position (const_tree field)
{
return tree_low_cst (bit_position (field), 0);
}
This is a tree of type sizetype. */
tree
-byte_position (tree field)
+byte_position (const_tree field)
{
return byte_from_pos (DECL_FIELD_OFFSET (field),
DECL_FIELD_BIT_OFFSET (field));
option of returning -1 like int_size_in_byte can. */
HOST_WIDE_INT
-int_byte_position (tree field)
+int_byte_position (const_tree field)
{
return tree_low_cst (byte_position (field), 0);
}
/* Return the strictest alignment, in bits, that T is known to have. */
unsigned int
-expr_align (tree t)
+expr_align (const_tree t)
{
unsigned int align0, align1;
switch (TREE_CODE (t))
{
- case NOP_EXPR: case CONVERT_EXPR: case NON_LVALUE_EXPR:
+ CASE_CONVERT: case NON_LVALUE_EXPR:
/* If we have conversions, we know that the alignment of the
object must meet each of the alignments of the types. */
align0 = expr_align (TREE_OPERAND (t, 0));
align1 = TYPE_ALIGN (TREE_TYPE (t));
return MAX (align0, align1);
- case GIMPLE_MODIFY_STMT:
- /* We should never ask for the alignment of a gimple statement. */
- gcc_unreachable ();
-
case SAVE_EXPR: case COMPOUND_EXPR: case MODIFY_EXPR:
case INIT_EXPR: case TARGET_EXPR: case WITH_CLEANUP_EXPR:
case CLEANUP_POINT_EXPR:
align1 = expr_align (TREE_OPERAND (t, 2));
return MIN (align0, align1);
+ /* FIXME: LABEL_DECL and CONST_DECL never have DECL_ALIGN set
+ meaningfully, it's always 1. */
case LABEL_DECL: case CONST_DECL:
case VAR_DECL: case PARM_DECL: case RESULT_DECL:
- if (DECL_ALIGN (t) != 0)
- return DECL_ALIGN (t);
- break;
-
case FUNCTION_DECL:
- return FUNCTION_BOUNDARY;
+ gcc_assert (DECL_ALIGN (t) != 0);
+ return DECL_ALIGN (t);
default:
break;
ARRAY_TYPE) minus one. This counts only elements of the top array. */
tree
-array_type_nelts (tree type)
+array_type_nelts (const_tree type)
{
tree index_type, min, max;
return NULL;
}
}
+
\f
+
+
+/* Return whether OP is a DECL whose address is function-invariant. */
+
+bool
+decl_address_invariant_p (const_tree op)
+{
+ /* The conditions below are slightly less strict than the one in
+ staticp. */
+
+ switch (TREE_CODE (op))
+ {
+ case PARM_DECL:
+ case RESULT_DECL:
+ case LABEL_DECL:
+ case FUNCTION_DECL:
+ return true;
+
+ case VAR_DECL:
+ if (((TREE_STATIC (op) || DECL_EXTERNAL (op))
+ && !DECL_DLLIMPORT_P (op))
+ || DECL_THREAD_LOCAL_P (op)
+ || DECL_CONTEXT (op) == current_function_decl
+ || decl_function_context (op) == current_function_decl)
+ return true;
+ break;
+
+ case CONST_DECL:
+ if ((TREE_STATIC (op) || DECL_EXTERNAL (op))
+ || decl_function_context (op) == current_function_decl)
+ return true;
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+
+/* Return true if T is function-invariant (internal function, does
+ not handle arithmetic; that's handled in skip_simple_arithmetic and
+ tree_invariant_p). */
+
+static bool tree_invariant_p (tree t);
+
+static bool
+tree_invariant_p_1 (tree t)
+{
+ tree op;
+
+ if (TREE_CONSTANT (t)
+ || (TREE_READONLY (t) && !TREE_SIDE_EFFECTS (t)))
+ return true;
+
+ switch (TREE_CODE (t))
+ {
+ case SAVE_EXPR:
+ return true;
+
+ case ADDR_EXPR:
+ op = TREE_OPERAND (t, 0);
+ while (handled_component_p (op))
+ {
+ switch (TREE_CODE (op))
+ {
+ case ARRAY_REF:
+ case ARRAY_RANGE_REF:
+ if (!tree_invariant_p (TREE_OPERAND (op, 1))
+ || TREE_OPERAND (op, 2) != NULL_TREE
+ || TREE_OPERAND (op, 3) != NULL_TREE)
+ return false;
+ break;
+
+ case COMPONENT_REF:
+ if (TREE_OPERAND (op, 2) != NULL_TREE)
+ return false;
+ break;
+
+ default:;
+ }
+ op = TREE_OPERAND (op, 0);
+ }
+
+ return CONSTANT_CLASS_P (op) || decl_address_invariant_p (op);
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+/* Return true if T is function-invariant. */
+
+static bool
+tree_invariant_p (tree t)
+{
+ tree inner = skip_simple_arithmetic (t);
+ return tree_invariant_p_1 (inner);
+}
+
/* Wrap a SAVE_EXPR around EXPR, if appropriate.
Do this to any expression which may be used in more than one place,
but must be evaluated only once.
Since it is no problem to reevaluate literals, we just return the
literal node. */
inner = skip_simple_arithmetic (t);
+ if (TREE_CODE (inner) == ERROR_MARK)
+ return inner;
- if (TREE_INVARIANT (inner)
- || (TREE_READONLY (inner) && ! TREE_SIDE_EFFECTS (inner))
- || TREE_CODE (inner) == SAVE_EXPR
- || TREE_CODE (inner) == ERROR_MARK)
+ if (tree_invariant_p_1 (inner))
return t;
/* If INNER contains a PLACEHOLDER_EXPR, we must evaluate it each time, since
value was computed on both sides of the jump. So make sure it isn't
eliminated as dead. */
TREE_SIDE_EFFECTS (t) = 1;
- TREE_INVARIANT (t) = 1;
return t;
}
inner = TREE_OPERAND (inner, 0);
else if (BINARY_CLASS_P (inner))
{
- if (TREE_INVARIANT (TREE_OPERAND (inner, 1)))
+ if (tree_invariant_p (TREE_OPERAND (inner, 1)))
inner = TREE_OPERAND (inner, 0);
- else if (TREE_INVARIANT (TREE_OPERAND (inner, 0)))
+ else if (tree_invariant_p (TREE_OPERAND (inner, 0)))
inner = TREE_OPERAND (inner, 1);
else
break;
/* Return which tree structure is used by T. */
enum tree_node_structure_enum
-tree_node_structure (tree t)
+tree_node_structure (const_tree t)
{
- enum tree_code code = TREE_CODE (t);
+ const enum tree_code code = TREE_CODE (t);
switch (TREE_CODE_CLASS (code))
{
return TS_FUNCTION_DECL;
case SYMBOL_MEMORY_TAG:
case NAME_MEMORY_TAG:
- case STRUCT_FIELD_TAG:
case MEMORY_PARTITION_TAG:
return TS_MEMORY_TAG;
default:
case tcc_statement:
case tcc_vl_exp:
return TS_EXP;
- case tcc_gimple_stmt:
- return TS_GIMPLE_STATEMENT;
default: /* tcc_constant and tcc_exceptional */
break;
}
/* tcc_constant cases. */
case INTEGER_CST: return TS_INT_CST;
case REAL_CST: return TS_REAL_CST;
+ case FIXED_CST: return TS_FIXED_CST;
case COMPLEX_CST: return TS_COMPLEX;
case VECTOR_CST: return TS_VECTOR;
case STRING_CST: return TS_STRING;
/* tcc_exceptional cases. */
- /* FIXME tuples: eventually this should be TS_BASE. For now, nothing
- returns TS_BASE. */
case ERROR_MARK: return TS_COMMON;
case IDENTIFIER_NODE: return TS_IDENTIFIER;
case TREE_LIST: return TS_LIST;
case TREE_VEC: return TS_VEC;
- case PHI_NODE: return TS_PHI_NODE;
case SSA_NAME: return TS_SSA_NAME;
case PLACEHOLDER_EXPR: return TS_COMMON;
case STATEMENT_LIST: return TS_STATEMENT_LIST;
case BLOCK: return TS_BLOCK;
case CONSTRUCTOR: return TS_CONSTRUCTOR;
case TREE_BINFO: return TS_BINFO;
- case VALUE_HANDLE: return TS_VALUE_HANDLE;
case OMP_CLAUSE: return TS_OMP_CLAUSE;
+ case OPTIMIZATION_NODE: return TS_OPTIMIZATION;
+ case TARGET_OPTION_NODE: return TS_TARGET_OPTION;
default:
gcc_unreachable ();
or offset that depends on a field within a record. */
bool
-contains_placeholder_p (tree exp)
+contains_placeholder_p (const_tree exp)
{
enum tree_code code;
{
case CALL_EXPR:
{
- tree arg;
- call_expr_arg_iterator iter;
- FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
+ const_tree arg;
+ const_call_expr_arg_iterator iter;
+ FOR_EACH_CONST_CALL_EXPR_ARG (arg, iter, exp)
if (CONTAINS_PLACEHOLDER_P (arg))
return 1;
return 0;
(for QUAL_UNION_TYPE) and field positions. */
static bool
-type_contains_placeholder_1 (tree type)
+type_contains_placeholder_1 (const_tree type)
{
/* If the size contains a placeholder or the parent type (component type in
the case of arrays) type involves a placeholder, this type does. */
case INTEGER_TYPE:
case REAL_TYPE:
+ case FIXED_POINT_TYPE:
/* Here we just check the bounds. */
return (CONTAINS_PLACEHOLDER_P (TYPE_MIN_VALUE (type))
|| CONTAINS_PLACEHOLDER_P (TYPE_MAX_VALUE (type)));
{
enum tree_code code = TREE_CODE (exp);
tree op0, op1, op2, op3;
- tree new;
- tree inner;
+ tree new, inner;
/* We handle TREE_LIST and COMPONENT_REF separately. */
if (code == TREE_LIST)
{
tree copy = NULL_TREE;
int i;
- int n = TREE_OPERAND_LENGTH (exp);
- for (i = 1; i < n; i++)
+
+ for (i = 1; i < TREE_OPERAND_LENGTH (exp); i++)
{
tree op = TREE_OPERAND (exp, i);
- tree newop = SUBSTITUTE_IN_EXPR (op, f, r);
- if (newop != op)
+ tree new_op = SUBSTITUTE_IN_EXPR (op, f, r);
+ if (new_op != op)
{
- copy = copy_node (exp);
- TREE_OPERAND (copy, i) = newop;
+ if (!copy)
+ copy = copy_node (exp);
+ TREE_OPERAND (copy, i) = new_op;
}
}
+
if (copy)
new = fold (copy);
else
return exp;
}
+ break;
default:
gcc_unreachable ();
{
tree copy = NULL_TREE;
int i;
- int n = TREE_OPERAND_LENGTH (exp);
- for (i = 1; i < n; i++)
+
+ for (i = 1; i < TREE_OPERAND_LENGTH (exp); i++)
{
tree op = TREE_OPERAND (exp, i);
- tree newop = SUBSTITUTE_PLACEHOLDER_IN_EXPR (op, obj);
- if (newop != op)
+ tree new_op = SUBSTITUTE_PLACEHOLDER_IN_EXPR (op, obj);
+ if (new_op != op)
{
if (!copy)
copy = copy_node (exp);
- TREE_OPERAND (copy, i) = newop;
+ TREE_OPERAND (copy, i) = new_op;
}
}
+
if (copy)
return fold (copy);
else
/* No action is needed in this case. */
return ref;
- case NOP_EXPR:
- case CONVERT_EXPR:
+ CASE_CONVERT:
case FLOAT_EXPR:
case FIX_TRUNC_EXPR:
result = build_nt (code, stabilize_reference (TREE_OPERAND (ref, 0)));
ignore things that are actual constant or that already have been
handled by this function. */
- if (TREE_INVARIANT (e))
+ if (tree_invariant_p (e))
return e;
switch (TREE_CODE_CLASS (code))
TREE_READONLY (result) = TREE_READONLY (e);
TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (e);
TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e);
- TREE_INVARIANT (result) = 1;
return result;
}
/* Low-level constructors for expressions. */
/* A helper function for build1 and constant folders. Set TREE_CONSTANT,
- TREE_INVARIANT, and TREE_SIDE_EFFECTS for an ADDR_EXPR. */
+ and TREE_SIDE_EFFECTS for an ADDR_EXPR. */
void
recompute_tree_invariant_for_addr_expr (tree t)
{
tree node;
- bool tc = true, ti = true, se = false;
+ bool tc = true, se = false;
/* We started out assuming this address is both invariant and constant, but
does not have side effects. Now go down any handled components and see if
??? Note that this code makes no attempt to deal with the case where
taking the address of something causes a copy due to misalignment. */
-#define UPDATE_TITCSE(NODE) \
+#define UPDATE_FLAGS(NODE) \
do { tree _node = (NODE); \
- if (_node && !TREE_INVARIANT (_node)) ti = false; \
if (_node && !TREE_CONSTANT (_node)) tc = false; \
if (_node && TREE_SIDE_EFFECTS (_node)) se = true; } while (0)
|| TREE_CODE (node) == ARRAY_RANGE_REF)
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (node, 0))) == ARRAY_TYPE)
{
- UPDATE_TITCSE (TREE_OPERAND (node, 1));
+ UPDATE_FLAGS (TREE_OPERAND (node, 1));
if (TREE_OPERAND (node, 2))
- UPDATE_TITCSE (TREE_OPERAND (node, 2));
+ UPDATE_FLAGS (TREE_OPERAND (node, 2));
if (TREE_OPERAND (node, 3))
- UPDATE_TITCSE (TREE_OPERAND (node, 3));
+ UPDATE_FLAGS (TREE_OPERAND (node, 3));
}
/* Likewise, just because this is a COMPONENT_REF doesn't mean we have a
FIELD_DECL, apparently. The G++ front end can put something else
&& TREE_CODE (TREE_OPERAND (node, 1)) == FIELD_DECL)
{
if (TREE_OPERAND (node, 2))
- UPDATE_TITCSE (TREE_OPERAND (node, 2));
+ UPDATE_FLAGS (TREE_OPERAND (node, 2));
}
else if (TREE_CODE (node) == BIT_FIELD_REF)
- UPDATE_TITCSE (TREE_OPERAND (node, 2));
+ UPDATE_FLAGS (TREE_OPERAND (node, 2));
}
- node = lang_hooks.expr_to_decl (node, &tc, &ti, &se);
+ node = lang_hooks.expr_to_decl (node, &tc, &se);
/* Now see what's inside. If it's an INDIRECT_REF, copy our properties from
- the address, since &(*a)->b is a form of addition. 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. */
+ the address, since &(*a)->b is a form of addition. If it's a constant, the
+ address is constant too. If it's a decl, its address is constant if the
+ decl is static. Everything else is not constant and, furthermore,
+ taking the address of a volatile variable is not volatile. */
if (TREE_CODE (node) == INDIRECT_REF)
- UPDATE_TITCSE (TREE_OPERAND (node, 0));
- else if (DECL_P (node))
- {
- if (staticp (node))
- ;
- else if (decl_function_context (node) == current_function_decl
- /* Addresses of thread-local variables are invariant. */
- || (TREE_CODE (node) == VAR_DECL
- && DECL_THREAD_LOCAL_P (node)))
- tc = false;
- else
- ti = tc = false;
- }
+ UPDATE_FLAGS (TREE_OPERAND (node, 0));
else if (CONSTANT_CLASS_P (node))
;
+ else if (DECL_P (node))
+ tc &= (staticp (node) != NULL_TREE);
else
{
- ti = tc = false;
+ tc = false;
se |= TREE_SIDE_EFFECTS (node);
}
+
TREE_CONSTANT (t) = tc;
- TREE_INVARIANT (t) = ti;
TREE_SIDE_EFFECTS (t) = se;
-#undef UPDATE_TITCSE
+#undef UPDATE_FLAGS
}
/* Build an expression of code CODE, data type TYPE, and operands as
gcc_assert (TREE_CODE_LENGTH (code) == 1);
- t = ggc_alloc_zone_pass_stat (length, &tree_zone);
+ t = (tree) ggc_alloc_zone_pass_stat (length, &tree_zone);
memset (t, 0, sizeof (struct tree_common));
TREE_SET_CODE (t, code);
TREE_TYPE (t) = type;
-#ifdef USE_MAPPED_LOCATION
SET_EXPR_LOCATION (t, UNKNOWN_LOCATION);
-#else
- SET_EXPR_LOCUS (t, NULL);
-#endif
TREE_OPERAND (t, 0) = node;
TREE_BLOCK (t) = NULL_TREE;
if (node && !TYPE_P (node))
&& node && !TYPE_P (node)
&& TREE_CONSTANT (node))
TREE_CONSTANT (t) = 1;
- if ((TREE_CODE_CLASS (code) == tcc_unary || code == VIEW_CONVERT_EXPR)
- && node && TREE_INVARIANT (node))
- TREE_INVARIANT (t) = 1;
if (TREE_CODE_CLASS (code) == tcc_reference
&& node && TREE_THIS_VOLATILE (node))
TREE_THIS_VOLATILE (t) = 1;
read_only = 0; \
if (!TREE_CONSTANT (arg##N)) \
constant = 0; \
- if (!TREE_INVARIANT (arg##N)) \
- invariant = 0; \
} \
} while (0)
tree
build2_stat (enum tree_code code, tree tt, tree arg0, tree arg1 MEM_STAT_DECL)
{
- bool constant, read_only, side_effects, invariant;
+ bool constant, read_only, side_effects;
tree t;
gcc_assert (TREE_CODE_LENGTH (code) == 2);
-#if 1
- /* FIXME tuples: Statement's aren't expressions! */
- if (code == GIMPLE_MODIFY_STMT)
- return build_gimple_modify_stmt_stat (arg0, arg1 PASS_MEM_STAT);
-#else
- /* Must use build_gimple_modify_stmt to construct GIMPLE_MODIFY_STMTs. */
- gcc_assert (code != GIMPLE_MODIFY_STMT);
-#endif
-
if ((code == MINUS_EXPR || code == PLUS_EXPR || code == MULT_EXPR)
&& arg0 && arg1 && tt && POINTER_TYPE_P (tt))
gcc_assert (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST);
if (code == POINTER_PLUS_EXPR && arg0 && arg1 && tt)
gcc_assert (POINTER_TYPE_P (tt) && POINTER_TYPE_P (TREE_TYPE (arg0))
- && TREE_CODE (TREE_TYPE (arg1)) == INTEGER_TYPE
+ && INTEGRAL_TYPE_P (TREE_TYPE (arg1))
&& useless_type_conversion_p (sizetype, TREE_TYPE (arg1)));
t = make_node_stat (code PASS_MEM_STAT);
|| TREE_CODE_CLASS (code) == tcc_binary);
read_only = 1;
side_effects = TREE_SIDE_EFFECTS (t);
- invariant = constant;
PROCESS_ARG(0);
PROCESS_ARG(1);
TREE_READONLY (t) = read_only;
TREE_CONSTANT (t) = constant;
- TREE_INVARIANT (t) = invariant;
TREE_SIDE_EFFECTS (t) = side_effects;
TREE_THIS_VOLATILE (t)
= (TREE_CODE_CLASS (code) == tcc_reference
}
-/* Build a GIMPLE_MODIFY_STMT node. This tree code doesn't have a
- type, so we can't use build2 (a.k.a. build2_stat). */
-
-tree
-build_gimple_modify_stmt_stat (tree arg0, tree arg1 MEM_STAT_DECL)
-{
- tree t;
-
- t = make_node_stat (GIMPLE_MODIFY_STMT PASS_MEM_STAT);
- /* ?? We don't care about setting flags for tuples... */
- GIMPLE_STMT_OPERAND (t, 0) = arg0;
- GIMPLE_STMT_OPERAND (t, 1) = arg1;
- return t;
-}
-
tree
build3_stat (enum tree_code code, tree tt, tree arg0, tree arg1,
tree arg2 MEM_STAT_DECL)
{
- bool constant, read_only, side_effects, invariant;
+ bool constant, read_only, side_effects;
tree t;
gcc_assert (TREE_CODE_LENGTH (code) == 3);
build4_stat (enum tree_code code, tree tt, tree arg0, tree arg1,
tree arg2, tree arg3 MEM_STAT_DECL)
{
- bool constant, read_only, side_effects, invariant;
+ bool constant, read_only, side_effects;
tree t;
gcc_assert (TREE_CODE_LENGTH (code) == 4);
build5_stat (enum tree_code code, tree tt, tree arg0, tree arg1,
tree arg2, tree arg3, tree arg4 MEM_STAT_DECL)
{
- bool constant, read_only, side_effects, invariant;
+ bool constant, read_only, side_effects;
tree t;
gcc_assert (TREE_CODE_LENGTH (code) == 5);
tree arg2, tree arg3, tree arg4, tree arg5,
tree arg6 MEM_STAT_DECL)
{
- bool constant, read_only, side_effects, invariant;
+ bool constant, read_only, side_effects;
tree t;
gcc_assert (code == TARGET_MEM_REF);
if (code == VAR_DECL || code == PARM_DECL || code == RESULT_DECL)
layout_decl (t, 0);
- else if (code == FUNCTION_DECL)
- {
- DECL_MODE (t) = FUNCTION_MODE;
- DECL_ALIGN (t) = FUNCTION_BOUNDARY;
- }
return t;
}
return block;
}
-#if 1 /* ! defined(USE_MAPPED_LOCATION) */
-/* ??? gengtype doesn't handle conditionals */
-static GTY(()) source_locus last_annotated_node;
-#endif
-
-#ifdef USE_MAPPED_LOCATION
-
expanded_location
expand_location (source_location loc)
{
xloc.file = NULL;
xloc.line = 0;
xloc.column = 0;
+ xloc.sysp = 0;
}
else
{
- const struct line_map *map = linemap_lookup (&line_table, loc);
+ 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);
+ xloc.sysp = map->sysp != 0;
};
return xloc;
}
-#else
-
-/* Record the exact location where an expression or an identifier were
- encountered. */
-
-void
-annotate_with_file_line (tree node, const char *file, int line)
-{
- /* Roughly one percent of the calls to this function are to annotate
- a node with the same information already attached to that node!
- Just return instead of wasting memory. */
- if (EXPR_LOCUS (node)
- && EXPR_LINENO (node) == line
- && (EXPR_FILENAME (node) == file
- || !strcmp (EXPR_FILENAME (node), file)))
- {
- last_annotated_node = EXPR_LOCUS (node);
- return;
- }
-
- /* In heavily macroized code (such as GCC itself) this single
- entry cache can reduce the number of allocations by more
- than half. */
- if (last_annotated_node
- && last_annotated_node->line == line
- && (last_annotated_node->file == file
- || !strcmp (last_annotated_node->file, file)))
- {
- SET_EXPR_LOCUS (node, last_annotated_node);
- return;
- }
-
- SET_EXPR_LOCUS (node, ggc_alloc (sizeof (location_t)));
- EXPR_LINENO (node) = line;
- EXPR_FILENAME (node) = file;
- last_annotated_node = EXPR_LOCUS (node);
-}
-
-void
-annotate_with_locus (tree node, location_t locus)
-{
- annotate_with_file_line (node, locus.file, locus.line);
-}
-#endif
\f
/* Source location accessor functions. */
-/* The source location of this expression. Non-tree_exp nodes such as
- decls and constants can be shared among multiple locations, so
- return nothing. */
-location_t
-expr_location (tree node)
-{
-#ifdef USE_MAPPED_LOCATION
- if (GIMPLE_STMT_P (node))
- return GIMPLE_STMT_LOCUS (node);
- return EXPR_P (node) ? node->exp.locus : UNKNOWN_LOCATION;
-#else
- if (GIMPLE_STMT_P (node))
- return EXPR_HAS_LOCATION (node)
- ? *GIMPLE_STMT_LOCUS (node) : UNKNOWN_LOCATION;
- return EXPR_HAS_LOCATION (node) ? *node->exp.locus : UNKNOWN_LOCATION;
-#endif
-}
-
-void
-set_expr_location (tree node, location_t locus)
-{
-#ifdef USE_MAPPED_LOCATION
- if (GIMPLE_STMT_P (node))
- GIMPLE_STMT_LOCUS (node) = locus;
- else
- EXPR_CHECK (node)->exp.locus = locus;
-#else
- annotate_with_locus (node, locus);
-#endif
-}
-
-bool
-expr_has_location (tree node)
-{
-#ifdef USE_MAPPED_LOCATION
- return expr_location (node) != UNKNOWN_LOCATION;
-#else
- return expr_locus (node) != NULL;
-#endif
-}
-
-#ifdef USE_MAPPED_LOCATION
-source_location *
-#else
-source_locus
-#endif
-expr_locus (tree node)
-{
-#ifdef USE_MAPPED_LOCATION
- if (GIMPLE_STMT_P (node))
- return &GIMPLE_STMT_LOCUS (node);
- return EXPR_P (node) ? &node->exp.locus : (location_t *) NULL;
-#else
- if (GIMPLE_STMT_P (node))
- return GIMPLE_STMT_LOCUS (node);
- /* ?? The cast below was originally "(location_t *)" in the macro,
- but that makes no sense. ?? */
- return EXPR_P (node) ? node->exp.locus : (source_locus) NULL;
-#endif
-}
-
void
-set_expr_locus (tree node,
-#ifdef USE_MAPPED_LOCATION
- source_location *loc
-#else
- source_locus loc
-#endif
- )
+set_expr_locus (tree node, source_location *loc)
{
-#ifdef USE_MAPPED_LOCATION
if (loc == NULL)
- {
- if (GIMPLE_STMT_P (node))
- GIMPLE_STMT_LOCUS (node) = UNKNOWN_LOCATION;
- else
- EXPR_CHECK (node)->exp.locus = UNKNOWN_LOCATION;
- }
- else
- {
- if (GIMPLE_STMT_P (node))
- GIMPLE_STMT_LOCUS (node) = *loc;
- else
- EXPR_CHECK (node)->exp.locus = *loc;
- }
-#else
- if (GIMPLE_STMT_P (node))
- GIMPLE_STMT_LOCUS (node) = loc;
+ EXPR_CHECK (node)->exp.locus = UNKNOWN_LOCATION;
else
- EXPR_CHECK (node)->exp.locus = loc;
-#endif
-}
-
-const char **
-expr_filename (tree node)
-{
-#ifdef USE_MAPPED_LOCATION
- if (GIMPLE_STMT_P (node))
- return &LOCATION_FILE (GIMPLE_STMT_LOCUS (node));
- return &LOCATION_FILE (EXPR_CHECK (node)->exp.locus);
-#else
- if (GIMPLE_STMT_P (node))
- return &GIMPLE_STMT_LOCUS (node)->file;
- return &(EXPR_CHECK (node)->exp.locus->file);
-#endif
-}
-
-int *
-expr_lineno (tree node)
-{
-#ifdef USE_MAPPED_LOCATION
- if (GIMPLE_STMT_P (node))
- return &LOCATION_LINE (GIMPLE_STMT_LOCUS (node));
- return &LOCATION_LINE (EXPR_CHECK (node)->exp.locus);
-#else
- if (GIMPLE_STMT_P (node))
- return &GIMPLE_STMT_LOCUS (node)->line;
- return &EXPR_CHECK (node)->exp.locus->line;
-#endif
+ EXPR_CHECK (node)->exp.locus = *loc;
}
\f
/* Return a declaration like DDECL except that its DECL_ATTRIBUTES
/* Produce good hash value combining VAL and VAL2. */
-static inline hashval_t
+hashval_t
iterative_hash_hashval_t (hashval_t val, hashval_t val2)
{
/* the golden ratio; an arbitrary value. */
/* Produce good hash value combining PTR and VAL2. */
static inline hashval_t
-iterative_hash_pointer (void *ptr, hashval_t val2)
+iterative_hash_pointer (const void *ptr, hashval_t val2)
{
if (sizeof (ptr) == sizeof (hashval_t))
return iterative_hash_hashval_t ((size_t) ptr, val2);
tree ntype;
enum tree_code code = TREE_CODE (ttype);
- ntype = copy_node (ttype);
-
- TYPE_POINTER_TO (ntype) = 0;
- TYPE_REFERENCE_TO (ntype) = 0;
- TYPE_ATTRIBUTES (ntype) = attribute;
+ /* Building a distinct copy of a tagged type is inappropriate; it
+ causes breakage in code that expects there to be a one-to-one
+ relationship between a struct and its fields.
+ build_duplicate_type is another solution (as used in
+ handle_transparent_union_attribute), but that doesn't play well
+ with the stronger C++ type identity model. */
+ if (TREE_CODE (ttype) == RECORD_TYPE
+ || TREE_CODE (ttype) == UNION_TYPE
+ || TREE_CODE (ttype) == QUAL_UNION_TYPE
+ || TREE_CODE (ttype) == ENUMERAL_TYPE)
+ {
+ warning (OPT_Wattributes,
+ "ignoring attributes applied to %qT after definition",
+ TYPE_MAIN_VARIANT (ttype));
+ return build_qualified_type (ttype, quals);
+ }
- if (TYPE_STRUCTURAL_EQUALITY_P (ttype))
- SET_TYPE_STRUCTURAL_EQUALITY (ntype);
- else
- TYPE_CANONICAL (ntype)
- = build_qualified_type (TYPE_CANONICAL (ttype), quals);
+ ntype = build_distinct_type_copy (ttype);
- /* Create a new main variant of TYPE. */
- TYPE_MAIN_VARIANT (ntype) = ntype;
- TYPE_NEXT_VARIANT (ntype) = 0;
+ TYPE_ATTRIBUTES (ntype) = attribute;
set_type_quals (ntype, TYPE_UNQUALIFIED);
hashcode = iterative_hash_object (code, hashcode);
hashcode = type_hash_list (TYPE_ARG_TYPES (ntype), hashcode);
break;
case ARRAY_TYPE:
- hashcode = iterative_hash_object (TYPE_HASH (TYPE_DOMAIN (ntype)),
- hashcode);
+ if (TYPE_DOMAIN (ntype))
+ hashcode = iterative_hash_object (TYPE_HASH (TYPE_DOMAIN (ntype)),
+ hashcode);
break;
case INTEGER_TYPE:
hashcode = iterative_hash_object
(TREE_INT_CST_HIGH (TYPE_MAX_VALUE (ntype)), hashcode);
break;
case REAL_TYPE:
+ case FIXED_POINT_TYPE:
{
unsigned int precision = TYPE_PRECISION (ntype);
hashcode = iterative_hash_object (precision, hashcode);
/* If the target-dependent attributes make NTYPE different from
its canonical type, we will need to use structural equality
checks for this qualified type. */
- if (!targetm.comp_type_attributes (ntype, ttype))
+ ttype = build_qualified_type (ttype, TYPE_UNQUALIFIED);
+ if (TYPE_STRUCTURAL_EQUALITY_P (ttype)
+ || !targetm.comp_type_attributes (ntype, ttype))
SET_TYPE_STRUCTURAL_EQUALITY (ntype);
+ else
+ TYPE_CANONICAL (ntype) = TYPE_CANONICAL (ttype);
ttype = build_qualified_type (ntype, quals);
}
+ else if (TYPE_QUALS (ttype) != quals)
+ ttype = build_qualified_type (ttype, quals);
return ttype;
}
their canonicalized form. */
static int
-is_attribute_with_length_p (const char *attr, int attr_len, tree ident)
+is_attribute_with_length_p (const char *attr, int attr_len, const_tree ident)
{
int ident_len;
const char *p;
We try both `text' and `__text__', ATTR may be either one. */
int
-is_attribute_p (const char *attr, tree ident)
+is_attribute_p (const char *attr, const_tree ident)
{
return is_attribute_with_length_p (attr, strlen (attr), ident);
}
if (is_attribute_with_length_p (attr_name, attr_len, TREE_PURPOSE (l)))
return l;
}
-
return NULL_TREE;
}
}
else if (DECL_DLLIMPORT_P (old) && !DECL_DLLIMPORT_P (new))
{
- /* Warn about overriding a symbol that has already been used. eg:
+ /* Warn about overriding a symbol that has already been used, e.g.:
extern int __attribute__ ((dllimport)) foo;
int* bar () {return &foo;}
int foo;
"after being referenced with dll linkage", new);
/* If we have used a variable's address with dllimport linkage,
keep the old DECL_DLLIMPORT_P flag: the ADDR_EXPR using the
- decl may already have had TREE_INVARIANT and TREE_CONSTANT
- computed.
+ decl may already have had TREE_CONSTANT computed.
We still remove the attribute so that assembler code refers
to '&foo rather than '_imp__foo'. */
if (TREE_CODE (old) == VAR_DECL && TREE_ADDRESSABLE (old))
return NULL_TREE;
}
+ if (TREE_CODE (node) == TYPE_DECL
+ && TREE_CODE (TREE_TYPE (node)) != RECORD_TYPE
+ && TREE_CODE (TREE_TYPE (node)) != UNION_TYPE)
+ {
+ *no_add_attrs = true;
+ warning (OPT_Wattributes, "%qs attribute ignored",
+ IDENTIFIER_POINTER (name));
+ return NULL_TREE;
+ }
+
/* Report error on dllimport ambiguities seen now before they cause
any damage. */
else if (is_attribute_p ("dllimport", name))
TYPE_RESTRICT (type) = (type_quals & TYPE_QUAL_RESTRICT) != 0;
}
-/* Returns true iff cand is equivalent to base with type_quals. */
+/* Returns true iff CAND is equivalent to BASE with TYPE_QUALS. */
bool
-check_qualified_type (tree cand, tree base, int type_quals)
+check_qualified_type (const_tree cand, const_tree base, int type_quals)
{
return (TYPE_QUALS (cand) == type_quals
&& TYPE_NAME (cand) == TYPE_NAME (base)
int
tree_map_base_eq (const void *va, const void *vb)
{
- const struct tree_map_base *a = va, *b = vb;
+ const struct tree_map_base *const a = (const struct tree_map_base *) va,
+ *const b = (const struct tree_map_base *) vb;
return (a->from == b->from);
}
int
tree_map_base_marked_p (const void *p)
{
- return ggc_marked_p (((struct tree_map_base *) p)->from);
+ return ggc_marked_p (((const struct tree_map_base *) p)->from);
}
unsigned int
struct tree_map_base in;
gcc_assert (VAR_OR_FUNCTION_DECL_P (decl));
- gcc_assert (TREE_CODE (decl) == VAR_DECL
- ? DECL_HAS_INIT_PRIORITY_P (decl)
- : DECL_STATIC_CONSTRUCTOR (decl));
in.from = decl;
- h = htab_find (init_priority_for_decl, &in);
+ h = (struct tree_priority_map *) htab_find (init_priority_for_decl, &in);
return h ? h->init : DEFAULT_INIT_PRIORITY;
}
struct tree_map_base in;
gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
- gcc_assert (DECL_STATIC_DESTRUCTOR (decl));
in.from = decl;
- h = htab_find (init_priority_for_decl, &in);
+ h = (struct tree_priority_map *) htab_find (init_priority_for_decl, &in);
return h ? h->fini : DEFAULT_INIT_PRIORITY;
}
in.base.from = decl;
loc = htab_find_slot (init_priority_for_decl, &in, INSERT);
- h = *loc;
+ h = (struct tree_priority_map *) *loc;
if (!h)
{
h = GGC_CNEW (struct tree_priority_map);
struct tree_map in;
in.base.from = from;
- h = htab_find_with_hash (restrict_base_for_decl, &in,
- htab_hash_pointer (from));
+ h = (struct tree_map *) htab_find_with_hash (restrict_base_for_decl, &in,
+ htab_hash_pointer (from));
return h ? h->to : NULL_TREE;
}
struct tree_map *h;
void **loc;
- h = ggc_alloc (sizeof (struct tree_map));
+ h = GGC_NEW (struct tree_map);
h->hash = htab_hash_pointer (from);
h->base.from = from;
h->to = to;
struct tree_map *h, in;
in.base.from = from;
- h = htab_find_with_hash (debug_expr_for_decl, &in, htab_hash_pointer (from));
+ h = (struct tree_map *) htab_find_with_hash (debug_expr_for_decl, &in,
+ htab_hash_pointer (from));
if (h)
return h->to;
return NULL_TREE;
struct tree_map *h;
void **loc;
- h = ggc_alloc (sizeof (struct tree_map));
+ h = GGC_NEW (struct tree_map);
h->hash = htab_hash_pointer (from);
h->base.from = from;
h->to = to;
struct tree_map *h, in;
in.base.from = from;
- h = htab_find_with_hash (value_expr_for_decl, &in, htab_hash_pointer (from));
+ h = (struct tree_map *) htab_find_with_hash (value_expr_for_decl, &in,
+ htab_hash_pointer (from));
if (h)
return h->to;
return NULL_TREE;
struct tree_map *h;
void **loc;
- h = ggc_alloc (sizeof (struct tree_map));
+ h = GGC_NEW (struct tree_map);
h->hash = htab_hash_pointer (from);
h->base.from = from;
h->to = to;
with types in the TREE_VALUE slots), by adding the hash codes
of the individual types. */
-unsigned int
-type_hash_list (tree list, hashval_t hashcode)
+static unsigned int
+type_hash_list (const_tree list, hashval_t hashcode)
{
- tree tail;
+ const_tree tail;
for (tail = list; tail; tail = TREE_CHAIN (tail))
if (TREE_VALUE (tail) != error_mark_node)
static int
type_hash_eq (const void *va, const void *vb)
{
- const struct type_hash *a = va, *b = vb;
+ const struct type_hash *const a = (const struct type_hash *) va,
+ *const b = (const struct type_hash *) vb;
/* First test the things that are the same for all types. */
if (a->hash != b->hash
|| tree_int_cst_equal (TYPE_MIN_VALUE (a->type),
TYPE_MIN_VALUE (b->type))));
+ case FIXED_POINT_TYPE:
+ return TYPE_SATURATING (a->type) == TYPE_SATURATING (b->type);
+
case OFFSET_TYPE:
return TYPE_OFFSET_BASETYPE (a->type) == TYPE_OFFSET_BASETYPE (b->type);
TYPE_FIELDS (b->type))));
case FUNCTION_TYPE:
- return (TYPE_ARG_TYPES (a->type) == TYPE_ARG_TYPES (b->type)
- || (TYPE_ARG_TYPES (a->type)
- && TREE_CODE (TYPE_ARG_TYPES (a->type)) == TREE_LIST
- && TYPE_ARG_TYPES (b->type)
- && TREE_CODE (TYPE_ARG_TYPES (b->type)) == TREE_LIST
- && type_list_equal (TYPE_ARG_TYPES (a->type),
- TYPE_ARG_TYPES (b->type))));
+ if (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;
default:
return 0;
}
+
+ if (lang_hooks.types.type_hash_eq != NULL)
+ return lang_hooks.types.type_hash_eq (a->type, b->type);
+
+ return 1;
}
/* Return the cached hash value. */
in.hash = hashcode;
in.type = type;
- h = htab_find_with_hash (type_hash_table, &in, hashcode);
+ h = (struct type_hash *) htab_find_with_hash (type_hash_table, &in,
+ hashcode);
if (h)
return h->type;
return NULL_TREE;
struct type_hash *h;
void **loc;
- h = ggc_alloc (sizeof (struct type_hash));
+ h = GGC_NEW (struct type_hash);
h->hash = hashcode;
h->type = type;
loc = htab_find_slot_with_hash (type_hash_table, h, hashcode, INSERT);
- *(struct type_hash **) loc = h;
+ *loc = (void *)h;
}
/* Given TYPE, and HASHCODE its hash code, return the canonical
static int
type_hash_marked_p (const void *p)
{
- tree type = ((struct type_hash *) p)->type;
+ const_tree const type = ((const struct type_hash *) p)->type;
return ggc_marked_p (type) || TYPE_SYMTAB_POINTER (type);
}
with names in the TREE_PURPOSE slots and args in the TREE_VALUE slots),
by adding the hash codes of the individual attributes. */
-unsigned int
-attribute_hash_list (tree list, hashval_t hashcode)
+static unsigned int
+attribute_hash_list (const_tree list, hashval_t hashcode)
{
- tree tail;
+ const_tree tail;
for (tail = list; tail; tail = TREE_CHAIN (tail))
/* ??? Do we want to add in TREE_VALUE too? */
equivalent to l1. */
int
-attribute_list_equal (tree l1, tree l2)
+attribute_list_equal (const_tree l1, const_tree l2)
{
return attribute_list_contained (l1, l2)
&& attribute_list_contained (l2, l1);
correctly. */
int
-attribute_list_contained (tree l1, tree l2)
+attribute_list_contained (const_tree l1, const_tree l2)
{
- tree t1, t2;
+ const_tree t1, t2;
/* First check the obvious, maybe the lists are identical. */
if (l1 == l2)
for (; t2 != 0; t2 = TREE_CHAIN (t2))
{
- tree attr;
- for (attr = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (t2)), l1);
+ const_tree attr;
+ /* 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)))
Also, the TREE_PURPOSEs must match. */
int
-type_list_equal (tree l1, tree l2)
+type_list_equal (const_tree l1, const_tree l2)
{
- tree t1, t2;
+ const_tree t1, t2;
for (t1 = l1, t2 = l2; t1 && t2; t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
if (TREE_VALUE (t1) != TREE_VALUE (t2)
then this function counts only the ordinary arguments. */
int
-type_num_arguments (tree type)
+type_num_arguments (const_tree type)
{
int i = 0;
tree t;
represent the same constant value. */
int
-tree_int_cst_equal (tree t1, tree t2)
+tree_int_cst_equal (const_tree t1, const_tree t2)
{
if (t1 == t2)
return 1;
The precise way of comparison depends on their data type. */
int
-tree_int_cst_lt (tree t1, tree t2)
+tree_int_cst_lt (const_tree t1, const_tree t2)
{
if (t1 == t2)
return 0;
/* Returns -1 if T1 < T2, 0 if T1 == T2, and 1 if T1 > T2. */
int
-tree_int_cst_compare (tree t1, tree t2)
+tree_int_cst_compare (const_tree t1, const_tree t2)
{
if (tree_int_cst_lt (t1, t2))
return -1;
be represented in a single unsigned HOST_WIDE_INT. */
int
-host_integerp (tree t, int pos)
+host_integerp (const_tree t, int pos)
{
return (TREE_CODE (t) == INTEGER_CST
&& ((TREE_INT_CST_HIGH (t) == 0
&& (HOST_WIDE_INT) TREE_INT_CST_LOW (t) >= 0)
|| (! pos && TREE_INT_CST_HIGH (t) == -1
&& (HOST_WIDE_INT) TREE_INT_CST_LOW (t) < 0
- && !TYPE_UNSIGNED (TREE_TYPE (t)))
+ && (!TYPE_UNSIGNED (TREE_TYPE (t))
+ || (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE
+ && TYPE_IS_SIZETYPE (TREE_TYPE (t)))))
|| (pos && TREE_INT_CST_HIGH (t) == 0)));
}
be non-negative. We must be able to satisfy the above conditions. */
HOST_WIDE_INT
-tree_low_cst (tree t, int pos)
+tree_low_cst (const_tree t, int pos)
{
gcc_assert (host_integerp (t, pos));
return TREE_INT_CST_LOW (t);
/* Return the most significant bit of the integer constant T. */
int
-tree_int_cst_msb (tree t)
+tree_int_cst_msb (const_tree t)
{
int prec;
HOST_WIDE_INT h;
Note that -1 will never be returned if T's type is unsigned. */
int
-tree_int_cst_sgn (tree t)
+tree_int_cst_sgn (const_tree t)
{
if (TREE_INT_CST_LOW (t) == 0 && TREE_INT_CST_HIGH (t) == 0)
return 0;
are known to be equal; otherwise return 0. */
int
-simple_cst_list_equal (tree l1, tree l2)
+simple_cst_list_equal (const_tree l1, const_tree l2)
{
while (l1 != NULL_TREE && l2 != NULL_TREE)
{
this function. */
int
-simple_cst_equal (tree t1, tree t2)
+simple_cst_equal (const_tree t1, const_tree t2)
{
enum tree_code code1, code2;
int cmp;
case REAL_CST:
return REAL_VALUES_IDENTICAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2));
+ case FIXED_CST:
+ return FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (t1), TREE_FIXED_CST (t2));
+
case STRING_CST:
return (TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2)
&& ! memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
if (call_expr_nargs (t1) != call_expr_nargs (t2))
return 0;
{
- tree arg1, arg2;
- call_expr_arg_iterator iter1, iter2;
- for (arg1 = first_call_expr_arg (t1, &iter1),
- arg2 = first_call_expr_arg (t2, &iter2);
+ const_tree arg1, arg2;
+ const_call_expr_arg_iterator iter1, iter2;
+ for (arg1 = first_const_call_expr_arg (t1, &iter1),
+ arg2 = first_const_call_expr_arg (t2, &iter2);
arg1 && arg2;
- arg1 = next_call_expr_arg (&iter1),
- arg2 = next_call_expr_arg (&iter2))
+ arg1 = next_const_call_expr_arg (&iter1),
+ arg2 = next_const_call_expr_arg (&iter2))
{
cmp = simple_cst_equal (arg1, arg2);
if (cmp <= 0)
than U, respectively. */
int
-compare_tree_int (tree t, unsigned HOST_WIDE_INT u)
+compare_tree_int (const_tree t, unsigned HOST_WIDE_INT u)
{
if (tree_int_cst_sgn (t) < 0)
return -1;
}
/* Generate a hash value for an expression. This can be used iteratively
- by passing a previous result as the "val" argument.
+ by passing a previous result as the VAL argument.
This function is intended to produce the same hash for expressions which
would compare equal using operand_equal_p. */
hashval_t
-iterative_hash_expr (tree t, hashval_t val)
+iterative_hash_expr (const_tree t, hashval_t val)
{
int i;
enum tree_code code;
return iterative_hash_hashval_t (val2, val);
}
+ case FIXED_CST:
+ {
+ unsigned int val2 = fixed_hash (TREE_FIXED_CST_PTR (t));
+
+ return iterative_hash_hashval_t (val2, val);
+ }
case STRING_CST:
return iterative_hash (TREE_STRING_POINTER (t),
TREE_STRING_LENGTH (t), val);
return iterative_hash_expr (TREE_VECTOR_CST_ELTS (t), val);
case SSA_NAME:
- case VALUE_HANDLE:
/* we can just compare by pointer. */
return iterative_hash_pointer (t, val);
break;
}
}
+
+/* Generate a hash value for a pair of expressions. This can be used
+ iteratively by passing a previous result as the VAL argument.
+
+ The same hash value is always returned for a given pair of expressions,
+ regardless of the order in which they are presented. This is useful in
+ hashing the operands of commutative functions. */
+
+hashval_t
+iterative_hash_exprs_commutative (const_tree t1,
+ const_tree t2, hashval_t val)
+{
+ hashval_t one = iterative_hash_expr (t1, 0);
+ hashval_t two = iterative_hash_expr (t2, 0);
+ hashval_t t;
+
+ if (one > two)
+ t = one, one = two, two = t;
+ val = iterative_hash_hashval_t (one, val);
+ val = iterative_hash_hashval_t (two, val);
+
+ return val;
+}
\f
/* Constructors for pointer, array and function types.
(RECORD_TYPE, UNION_TYPE and ENUMERAL_TYPE nodes are
if (to_type == error_mark_node)
return error_mark_node;
+ /* If the pointed-to type has the may_alias attribute set, force
+ a TYPE_REF_CAN_ALIAS_ALL pointer to be generated. */
+ if (lookup_attribute ("may_alias", TYPE_ATTRIBUTES (to_type)))
+ can_alias_all = true;
+
/* In some cases, languages will have things that aren't a POINTER_TYPE
(such as a RECORD_TYPE for fat pointers in Ada) as TYPE_POINTER_TO.
In that case, return that type without regard to the rest of our
{
tree t;
+ if (to_type == error_mark_node)
+ return error_mark_node;
+
+ /* If the pointed-to type has the may_alias attribute set, force
+ a TYPE_REF_CAN_ALIAS_ALL pointer to be generated. */
+ if (lookup_attribute ("may_alias", TYPE_ATTRIBUTES (to_type)))
+ can_alias_all = true;
+
/* In some cases, languages will have things that aren't a REFERENCE_TYPE
(such as a RECORD_TYPE for fat pointers in Ada) as TYPE_REFERENCE_TO.
In that case, return that type without regard to the rest of our
return t;
}
-/* Return the TYPE of the elements comprising
- the innermost dimension of ARRAY. */
+/* Recursively examines the array elements of TYPE, until a non-array
+ element type is found. */
tree
-get_inner_array_type (tree array)
+strip_array_types (tree type)
{
- tree type = TREE_TYPE (array);
-
while (TREE_CODE (type) == ARRAY_TYPE)
type = TREE_TYPE (type);
}
/* Build a function type. The RETURN_TYPE is the type returned by the
- function. If additional arguments are provided, they are
- additional argument types. The list of argument types must always
- be terminated by NULL_TREE. */
+ function. If VAARGS is set, no void_type_node is appended to the
+ the list. ARGP muse be alway be terminated be a NULL_TREE. */
-tree
-build_function_type_list (tree return_type, ...)
+static tree
+build_function_type_list_1 (bool vaargs, tree return_type, va_list argp)
{
tree t, args, last;
- va_list p;
- va_start (p, return_type);
-
- t = va_arg (p, tree);
- for (args = NULL_TREE; t != NULL_TREE; t = va_arg (p, tree))
+ t = va_arg (argp, tree);
+ for (args = NULL_TREE; t != NULL_TREE; t = va_arg (argp, tree))
args = tree_cons (NULL_TREE, t, args);
- if (args == NULL_TREE)
+ if (vaargs)
+ {
+ last = args;
+ if (args != NULL_TREE)
+ args = nreverse (args);
+ gcc_assert (args != NULL_TREE && last != void_list_node);
+ }
+ else if (args == NULL_TREE)
args = void_list_node;
else
{
}
args = build_function_type (return_type, args);
+ return args;
+}
+
+/* Build a function type. The RETURN_TYPE is the type returned by the
+ function. If additional arguments are provided, they are
+ additional argument types. The list of argument types must always
+ be terminated by NULL_TREE. */
+
+tree
+build_function_type_list (tree return_type, ...)
+{
+ tree args;
+ va_list p;
+
+ va_start (p, return_type);
+ args = build_function_type_list_1 (false, return_type, p);
va_end (p);
return args;
}
+/* Build a variable argument function type. The RETURN_TYPE is the
+ type returned by the function. If additional arguments are provided,
+ they are additional argument types. The list of argument types must
+ always be terminated by NULL_TREE. */
+
+tree
+build_varargs_function_type_list (tree return_type, ...)
+{
+ tree args;
+ va_list p;
+
+ va_start (p, return_type);
+ args = build_function_type_list_1 (true, return_type, p);
+ va_end (p);
+
+ return args;
+}
+
/* 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
if (TYPE_STRUCTURAL_EQUALITY_P (basetype)
|| TYPE_STRUCTURAL_EQUALITY_P (type))
SET_TYPE_STRUCTURAL_EQUALITY (t);
- else if (TYPE_CANONICAL (basetype) != basetype
+ else if (TYPE_CANONICAL (TYPE_MAIN_VARIANT (basetype)) != basetype
|| TYPE_CANONICAL (type) != type)
TYPE_CANONICAL (t)
- = build_offset_type (TYPE_CANONICAL (basetype),
+ = build_offset_type (TYPE_CANONICAL (TYPE_MAIN_VARIANT (basetype)),
TYPE_CANONICAL (type));
}
= build_complex_type (TYPE_CANONICAL (component_type));
}
- /* If we are writing Dwarf2 output we need to create a name,
- since complex is a fundamental type. */
- if ((write_symbols == DWARF2_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG)
- && ! TYPE_NAME (t))
+ /* We need to create a name, since complex is a fundamental type. */
+ if (! TYPE_NAME (t))
{
const char *name;
if (component_type == char_type_node)
If FOR_TYPE is nonzero, we return a value which, if converted to
type FOR_TYPE, would be equivalent to converting OP to type FOR_TYPE.
- If FOR_TYPE is nonzero, unaligned bit-field references may be changed to the
- narrowest type that can hold the value, even if they don't exactly fit.
- Otherwise, bit-field references are changed to a narrower type
- only if they can be fetched directly from memory in that type.
-
OP must have integer, real or enumeral type. Pointers are not allowed!
There are some cases where the obvious value we could return
&& TYPE_UNSIGNED (type));
tree win = op;
- while (TREE_CODE (op) == NOP_EXPR
- || TREE_CODE (op) == CONVERT_EXPR)
+ while (CONVERT_EXPR_P (op))
{
int bitschange;
Let's avoid computing it if it does not affect WIN
and if UNS will not be needed again. */
if ((uns
- || TREE_CODE (op) == NOP_EXPR
- || TREE_CODE (op) == CONVERT_EXPR)
+ || CONVERT_EXPR_P (op))
&& TYPE_UNSIGNED (TREE_TYPE (op)))
{
uns = 1;
}
}
- if (TREE_CODE (op) == COMPONENT_REF
- /* Since type_for_size always gives an integer type. */
- && TREE_CODE (type) != REAL_TYPE
- /* Don't crash if field not laid out yet. */
- && DECL_SIZE (TREE_OPERAND (op, 1)) != 0
- && host_integerp (DECL_SIZE (TREE_OPERAND (op, 1)), 1))
- {
- unsigned int innerprec
- = tree_low_cst (DECL_SIZE (TREE_OPERAND (op, 1)), 1);
- int unsignedp = (DECL_UNSIGNED (TREE_OPERAND (op, 1))
- || TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op, 1))));
- type = lang_hooks.types.type_for_size (innerprec, unsignedp);
-
- /* We can get this structure field in the narrowest type it fits in.
- If FOR_TYPE is 0, do this only for a field that matches the
- narrower type exactly and is aligned for it
- The resulting extension to its nominal type (a fullword type)
- must fit the same conditions as for other extensions. */
-
- if (type != 0
- && INT_CST_LT_UNSIGNED (TYPE_SIZE (type), TYPE_SIZE (TREE_TYPE (op)))
- && (for_type || ! DECL_BIT_FIELD (TREE_OPERAND (op, 1)))
- && (! uns || final_prec <= innerprec || unsignedp))
- {
- win = build3 (COMPONENT_REF, type, TREE_OPERAND (op, 0),
- TREE_OPERAND (op, 1), NULL_TREE);
- TREE_SIDE_EFFECTS (win) = TREE_SIDE_EFFECTS (op);
- TREE_THIS_VOLATILE (win) = TREE_THIS_VOLATILE (op);
- }
- }
-
return win;
}
\f
if (TREE_CODE (op) == COMPONENT_REF
/* Since type_for_size always gives an integer type. */
&& TREE_CODE (TREE_TYPE (op)) != REAL_TYPE
+ && TREE_CODE (TREE_TYPE (op)) != FIXED_POINT_TYPE
/* Ensure field is laid out already. */
&& DECL_SIZE (TREE_OPERAND (op, 1)) != 0
&& host_integerp (DECL_SIZE (TREE_OPERAND (op, 1)), 1))
for type TYPE (an INTEGER_TYPE). */
int
-int_fits_type_p (tree c, tree type)
+int_fits_type_p (const_tree c, const_tree type)
{
tree type_low_bound = TYPE_MIN_VALUE (type);
tree type_high_bound = TYPE_MAX_VALUE (type);
precision of the type are returned instead. */
void
-get_type_static_bounds (tree type, mpz_t min, mpz_t max)
+get_type_static_bounds (const_tree type, mpz_t min, mpz_t max)
{
if (!POINTER_TYPE_P (type) && TYPE_MIN_VALUE (type)
&& TREE_CODE (TYPE_MIN_VALUE (type)) == INTEGER_CST)
}
}
+/* Return true if VAR is an automatic variable defined in function FN. */
+
+bool
+auto_var_in_fn_p (const_tree var, const_tree fn)
+{
+ return (DECL_P (var) && DECL_CONTEXT (var) == fn
+ && (((TREE_CODE (var) == VAR_DECL || TREE_CODE (var) == PARM_DECL)
+ && ! TREE_STATIC (var))
+ || TREE_CODE (var) == LABEL_DECL
+ || TREE_CODE (var) == RESULT_DECL));
+}
+
/* Subprogram of following function. Called by walk_tree.
Return *TP if it is an automatic variable or parameter of the
*walk_subtrees = 0;
else if (DECL_P (*tp)
- && lang_hooks.tree_inlining.auto_var_in_fn_p (*tp, fn))
+ && auto_var_in_fn_p (*tp, fn))
return *tp;
return NULL_TREE;
case INTEGER_TYPE:
case REAL_TYPE:
+ case FIXED_POINT_TYPE:
case ENUMERAL_TYPE:
case BOOLEAN_TYPE:
/* Scalar types are variably modified if their end points
NULL_TREE if there is no containing scope. */
tree
-get_containing_scope (tree t)
+get_containing_scope (const_tree t)
{
return (TYPE_P (t) ? TYPE_CONTEXT (t) : DECL_CONTEXT (t));
}
a FUNCTION_DECL, or zero if none. */
tree
-decl_function_context (tree decl)
+decl_function_context (const_tree decl)
{
tree context;
TYPE_DECLs and FUNCTION_DECLs are transparent to this function. */
tree
-decl_type_context (tree decl)
+decl_type_context (const_tree decl)
{
tree context = DECL_CONTEXT (decl);
determined. */
tree
-get_callee_fndecl (tree call)
+get_callee_fndecl (const_tree call)
{
tree addr;
if (call == error_mark_node)
- return call;
+ return error_mark_node;
/* It's invalid to call this function with anything but a
CALL_EXPR. */
file = input_filename;
len = strlen (file);
- q = alloca (9 * 2 + len + 1);
+ q = (char *) alloca (9 * 2 + len + 1);
memcpy (q, file, len + 1);
clean_symbol_name (q);
p = q;
}
- buf = alloca (sizeof (FILE_FUNCTION_FORMAT) + strlen (p) + strlen (type));
+ buf = (char *) alloca (sizeof (FILE_FUNCTION_FORMAT) + strlen (p)
+ + strlen (type));
/* Set up the name of the file-level functions we may need.
Use a global object (which is already required to be unique over
are of the caller. */
void
-tree_check_failed (const tree node, const char *file,
+tree_check_failed (const_tree node, const char *file,
int line, const char *function, ...)
{
va_list args;
- char *buffer;
+ const char *buffer;
unsigned length = 0;
int code;
va_end (args);
if (length)
{
+ char *tmp;
va_start (args, function);
length += strlen ("expected ");
- buffer = alloca (length);
+ buffer = tmp = (char *) alloca (length);
length = 0;
while ((code = va_arg (args, int)))
{
const char *prefix = length ? " or " : "expected ";
- strcpy (buffer + length, prefix);
+ strcpy (tmp + length, prefix);
length += strlen (prefix);
- strcpy (buffer + length, tree_code_name[code]);
+ strcpy (tmp + length, tree_code_name[code]);
length += strlen (tree_code_name[code]);
}
va_end (args);
}
else
- buffer = (char *)"unexpected node";
+ buffer = "unexpected node";
internal_error ("tree check: %s, have %s in %s, at %s:%d",
buffer, tree_code_name[TREE_CODE (node)],
the caller. */
void
-tree_not_check_failed (const tree node, const char *file,
+tree_not_check_failed (const_tree node, const char *file,
int line, const char *function, ...)
{
va_list args;
length += 4 + strlen (tree_code_name[code]);
va_end (args);
va_start (args, function);
- buffer = alloca (length);
+ buffer = (char *) alloca (length);
length = 0;
while ((code = va_arg (args, int)))
{
code, given in CL. */
void
-tree_class_check_failed (const tree node, const enum tree_code_class cl,
+tree_class_check_failed (const_tree node, const enum tree_code_class cl,
const char *file, int line, const char *function)
{
internal_error
dozen codes, use the knowledge that they're all sequential. */
void
-tree_range_check_failed (const tree node, const char *file, int line,
+tree_range_check_failed (const_tree node, const char *file, int line,
const char *function, enum tree_code c1,
enum tree_code c2)
{
length += 4 + strlen (tree_code_name[c]);
length += strlen ("expected ");
- buffer = alloca (length);
+ buffer = (char *) alloca (length);
length = 0;
for (c = c1; c <= c2; ++c)
not have the specified code, given in CL. */
void
-tree_not_class_check_failed (const tree node, const enum tree_code_class cl,
+tree_not_class_check_failed (const_tree node, const enum tree_code_class cl,
const char *file, int line, const char *function)
{
internal_error
/* Similar to tree_check_failed but applied to OMP_CLAUSE codes. */
void
-omp_clause_check_failed (const tree node, const char *file, int line,
+omp_clause_check_failed (const_tree node, const char *file, int line,
const char *function, enum omp_clause_code code)
{
internal_error ("tree check: expected omp_clause %s, have %s in %s, at %s:%d",
/* Similar to tree_range_check_failed but applied to OMP_CLAUSE codes. */
void
-omp_clause_range_check_failed (const tree node, const char *file, int line,
+omp_clause_range_check_failed (const_tree node, const char *file, int line,
const char *function, enum omp_clause_code c1,
enum omp_clause_code c2)
{
length += 4 + strlen (omp_clause_code_name[c]);
length += strlen ("expected ");
- buffer = alloca (length);
+ buffer = (char *) alloca (length);
length = 0;
for (c = c1; c <= c2; ++c)
whether CODE contains the tree structure identified by EN. */
void
-tree_contains_struct_check_failed (const tree node,
+tree_contains_struct_check_failed (const_tree node,
const enum tree_node_structure_enum en,
const char *file, int line,
const char *function)
idx + 1, len, function, trim_filename (file), line);
}
-/* Similar to above, except that the check is for the bounds of a PHI_NODE's
- (dynamically sized) vector. */
-
-void
-phi_node_elt_check_failed (int idx, int len, const char *file, int line,
- const char *function)
-{
- internal_error
- ("tree check: accessed elt %d of phi_node with %d elts in %s, at %s:%d",
- idx + 1, len, function, trim_filename (file), line);
-}
-
/* Similar to above, except that the check is for the bounds of the operand
vector of an expression node EXP. */
void
-tree_operand_check_failed (int idx, tree exp, const char *file,
+tree_operand_check_failed (int idx, const_tree exp, const char *file,
int line, const char *function)
{
int code = TREE_CODE (exp);
operands of an OMP_CLAUSE node. */
void
-omp_clause_operand_check_failed (int idx, tree t, const char *file,
+omp_clause_operand_check_failed (int idx, const_tree t, const char *file,
int line, const char *function)
{
internal_error
return make_signed_type (size);
}
+/* Create or reuse a fract type by SIZE, UNSIGNEDP, and SATP. */
+
+static tree
+make_or_reuse_fract_type (unsigned size, int unsignedp, int satp)
+{
+ if (satp)
+ {
+ if (size == SHORT_FRACT_TYPE_SIZE)
+ return unsignedp ? sat_unsigned_short_fract_type_node
+ : sat_short_fract_type_node;
+ if (size == FRACT_TYPE_SIZE)
+ return unsignedp ? sat_unsigned_fract_type_node : sat_fract_type_node;
+ if (size == LONG_FRACT_TYPE_SIZE)
+ return unsignedp ? sat_unsigned_long_fract_type_node
+ : sat_long_fract_type_node;
+ if (size == LONG_LONG_FRACT_TYPE_SIZE)
+ return unsignedp ? sat_unsigned_long_long_fract_type_node
+ : sat_long_long_fract_type_node;
+ }
+ else
+ {
+ if (size == SHORT_FRACT_TYPE_SIZE)
+ return unsignedp ? unsigned_short_fract_type_node
+ : short_fract_type_node;
+ if (size == FRACT_TYPE_SIZE)
+ return unsignedp ? unsigned_fract_type_node : fract_type_node;
+ if (size == LONG_FRACT_TYPE_SIZE)
+ return unsignedp ? unsigned_long_fract_type_node
+ : long_fract_type_node;
+ if (size == LONG_LONG_FRACT_TYPE_SIZE)
+ return unsignedp ? unsigned_long_long_fract_type_node
+ : long_long_fract_type_node;
+ }
+
+ return make_fract_type (size, unsignedp, satp);
+}
+
+/* Create or reuse an accum type by SIZE, UNSIGNEDP, and SATP. */
+
+static tree
+make_or_reuse_accum_type (unsigned size, int unsignedp, int satp)
+{
+ if (satp)
+ {
+ if (size == SHORT_ACCUM_TYPE_SIZE)
+ return unsignedp ? sat_unsigned_short_accum_type_node
+ : sat_short_accum_type_node;
+ if (size == ACCUM_TYPE_SIZE)
+ return unsignedp ? sat_unsigned_accum_type_node : sat_accum_type_node;
+ if (size == LONG_ACCUM_TYPE_SIZE)
+ return unsignedp ? sat_unsigned_long_accum_type_node
+ : sat_long_accum_type_node;
+ if (size == LONG_LONG_ACCUM_TYPE_SIZE)
+ return unsignedp ? sat_unsigned_long_long_accum_type_node
+ : sat_long_long_accum_type_node;
+ }
+ else
+ {
+ if (size == SHORT_ACCUM_TYPE_SIZE)
+ return unsignedp ? unsigned_short_accum_type_node
+ : short_accum_type_node;
+ if (size == ACCUM_TYPE_SIZE)
+ return unsignedp ? unsigned_accum_type_node : accum_type_node;
+ if (size == LONG_ACCUM_TYPE_SIZE)
+ return unsignedp ? unsigned_long_accum_type_node
+ : long_accum_type_node;
+ if (size == LONG_LONG_ACCUM_TYPE_SIZE)
+ return unsignedp ? unsigned_long_long_accum_type_node
+ : long_long_accum_type_node;
+ }
+
+ return make_accum_type (size, unsignedp, satp);
+}
+
/* 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. */
complex_double_type_node = build_complex_type (double_type_node);
complex_long_double_type_node = build_complex_type (long_double_type_node);
+/* Make fixed-point nodes based on sat/non-sat and signed/unsigned. */
+#define MAKE_FIXED_TYPE_NODE(KIND,SIZE) \
+ sat_ ## KIND ## _type_node = \
+ make_sat_signed_ ## KIND ## _type (SIZE); \
+ sat_unsigned_ ## KIND ## _type_node = \
+ make_sat_unsigned_ ## KIND ## _type (SIZE); \
+ KIND ## _type_node = make_signed_ ## KIND ## _type (SIZE); \
+ unsigned_ ## KIND ## _type_node = \
+ make_unsigned_ ## KIND ## _type (SIZE);
+
+#define MAKE_FIXED_TYPE_NODE_WIDTH(KIND,WIDTH,SIZE) \
+ sat_ ## WIDTH ## KIND ## _type_node = \
+ make_sat_signed_ ## KIND ## _type (SIZE); \
+ sat_unsigned_ ## WIDTH ## KIND ## _type_node = \
+ make_sat_unsigned_ ## KIND ## _type (SIZE); \
+ WIDTH ## KIND ## _type_node = make_signed_ ## KIND ## _type (SIZE); \
+ unsigned_ ## WIDTH ## KIND ## _type_node = \
+ make_unsigned_ ## KIND ## _type (SIZE);
+
+/* Make fixed-point type nodes based on four different widths. */
+#define MAKE_FIXED_TYPE_NODE_FAMILY(N1,N2) \
+ MAKE_FIXED_TYPE_NODE_WIDTH (N1, short_, SHORT_ ## N2 ## _TYPE_SIZE) \
+ MAKE_FIXED_TYPE_NODE (N1, N2 ## _TYPE_SIZE) \
+ MAKE_FIXED_TYPE_NODE_WIDTH (N1, long_, LONG_ ## N2 ## _TYPE_SIZE) \
+ MAKE_FIXED_TYPE_NODE_WIDTH (N1, long_long_, LONG_LONG_ ## N2 ## _TYPE_SIZE)
+
+/* Make fixed-point mode nodes based on sat/non-sat and signed/unsigned. */
+#define MAKE_FIXED_MODE_NODE(KIND,NAME,MODE) \
+ NAME ## _type_node = \
+ make_or_reuse_signed_ ## KIND ## _type (GET_MODE_BITSIZE (MODE ## mode)); \
+ u ## NAME ## _type_node = \
+ make_or_reuse_unsigned_ ## KIND ## _type \
+ (GET_MODE_BITSIZE (U ## MODE ## mode)); \
+ sat_ ## NAME ## _type_node = \
+ make_or_reuse_sat_signed_ ## KIND ## _type \
+ (GET_MODE_BITSIZE (MODE ## mode)); \
+ sat_u ## NAME ## _type_node = \
+ make_or_reuse_sat_unsigned_ ## KIND ## _type \
+ (GET_MODE_BITSIZE (U ## MODE ## mode));
+
+ /* Fixed-point type and mode nodes. */
+ MAKE_FIXED_TYPE_NODE_FAMILY (fract, FRACT)
+ MAKE_FIXED_TYPE_NODE_FAMILY (accum, ACCUM)
+ MAKE_FIXED_MODE_NODE (fract, qq, QQ)
+ MAKE_FIXED_MODE_NODE (fract, hq, HQ)
+ MAKE_FIXED_MODE_NODE (fract, sq, SQ)
+ MAKE_FIXED_MODE_NODE (fract, dq, DQ)
+ MAKE_FIXED_MODE_NODE (fract, tq, TQ)
+ MAKE_FIXED_MODE_NODE (accum, ha, HA)
+ MAKE_FIXED_MODE_NODE (accum, sa, SA)
+ MAKE_FIXED_MODE_NODE (accum, da, DA)
+ MAKE_FIXED_MODE_NODE (accum, ta, TA)
+
{
tree t = targetm.build_builtin_va_list ();
if (ecf_flags & ECF_CONST)
TREE_READONLY (decl) = 1;
if (ecf_flags & ECF_PURE)
- DECL_IS_PURE (decl) = 1;
+ DECL_PURE_P (decl) = 1;
+ if (ecf_flags & ECF_LOOPING_CONST_OR_PURE)
+ DECL_LOOPING_CONST_OR_PURE_P (decl) = 1;
if (ecf_flags & ECF_NORETURN)
TREE_THIS_VOLATILE (decl) = 1;
if (ecf_flags & ECF_NOTHROW)
inner,
TREE_CHAIN (TYPE_ARG_TYPES (type)));
}
+ else if (TREE_CODE (type) == OFFSET_TYPE)
+ {
+ inner = reconstruct_complex_type (TREE_TYPE (type), bottom);
+ outer = build_offset_type (TYPE_OFFSET_BASETYPE (type), inner);
+ }
else
return bottom;
- TYPE_READONLY (outer) = TYPE_READONLY (type);
- TYPE_VOLATILE (outer) = TYPE_VOLATILE (type);
-
- return outer;
+ return build_qualified_type (outer, TYPE_QUALS (type));
}
/* Returns a vector tree node given a mode (integer, vector, or BLKmode) and
{
case MODE_VECTOR_INT:
case MODE_VECTOR_FLOAT:
+ case MODE_VECTOR_FRACT:
+ case MODE_VECTOR_UFRACT:
+ case MODE_VECTOR_ACCUM:
+ case MODE_VECTOR_UACCUM:
nunits = GET_MODE_NUNITS (mode);
break;
/* Given an initializer INIT, return TRUE if INIT is zero or some
aggregate of zeros. Otherwise return FALSE. */
bool
-initializer_zerop (tree init)
+initializer_zerop (const_tree init)
{
tree elt;
return real_zerop (init)
&& ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (init));
+ case FIXED_CST:
+ return fixed_zerop (init);
+
case COMPLEX_CST:
return integer_zerop (init)
|| (real_zerop (init)
length = omp_clause_num_ops[code];
size = (sizeof (struct tree_omp_clause) + (length - 1) * sizeof (tree));
- t = ggc_alloc (size);
+ t = GGC_NEWVAR (union tree_node, size);
memset (t, 0, size);
TREE_SET_CODE (t, OMP_CLAUSE);
OMP_CLAUSE_SET_CODE (t, code);
/* Calls have side-effects, except those to const or
pure functions. */
i = call_expr_flags (t);
- if (!(i & (ECF_CONST | ECF_PURE)))
+ if ((i & ECF_LOOPING_CONST_OR_PURE) || !(i & (ECF_CONST | ECF_PURE)))
side_effects = 1;
}
TREE_SIDE_EFFECTS (t) = side_effects;
tree_node_sizes[(int) e_kind] += length;
#endif
- t = ggc_alloc_zone_pass_stat (length, &tree_zone);
+ t = (tree) ggc_alloc_zone_pass_stat (length, &tree_zone);
memset (t, 0, length);
location. */
bool
-needs_to_live_in_memory (tree t)
+needs_to_live_in_memory (const_tree t)
{
if (TREE_CODE (t) == SSA_NAME)
t = SSA_NAME_VAR (t);
are compatible. It is assumed that the parent records are compatible. */
bool
-fields_compatible_p (tree f1, tree f2)
+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 orig_field;
}
-/* Return value of a constant X. */
+/* Return value of a constant X and sign-extend it. */
HOST_WIDE_INT
-int_cst_value (tree x)
+int_cst_value (const_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;
- gcc_assert (bits <= HOST_BITS_PER_WIDE_INT);
+ /* Make sure the sign-extended value will fit in a HOST_WIDE_INT. */
+ gcc_assert (TREE_INT_CST_HIGH (x) == 0
+ || TREE_INT_CST_HIGH (x) == -1);
- if (negative)
- val |= (~(unsigned HOST_WIDE_INT) 0) << (bits - 1) << 1;
- else
- val &= ~((~(unsigned HOST_WIDE_INT) 0) << (bits - 1) << 1);
+ if (bits < HOST_BITS_PER_WIDE_INT)
+ {
+ bool negative = ((val >> (bits - 1)) & 1) != 0;
+ if (negative)
+ val |= (~(unsigned HOST_WIDE_INT) 0) << (bits - 1) << 1;
+ else
+ val &= ~((~(unsigned HOST_WIDE_INT) 0) << (bits - 1) << 1);
+ }
return val;
}
and get the same result, only slower. */
int
-operand_equal_for_phi_arg_p (tree arg0, tree arg1)
+operand_equal_for_phi_arg_p (const_tree arg0, const_tree arg1)
{
if (arg0 == arg1)
return 1;
??? Use ffs if available? */
tree
-num_ending_zeros (tree x)
+num_ending_zeros (const_tree x)
{
unsigned HOST_WIDE_INT fr, nfr;
unsigned num, abits;
#define WALK_SUBTREE(NODE) \
do \
{ \
- result = walk_tree (&(NODE), func, data, pset); \
+ result = walk_tree_1 (&(NODE), func, data, pset, lh); \
if (result) \
return result; \
} \
static tree
walk_type_fields (tree type, walk_tree_fn func, void *data,
- struct pointer_set_t *pset)
+ struct pointer_set_t *pset, walk_tree_lh lh)
{
tree result = NULL_TREE;
and to avoid visiting a node more than once. */
tree
-walk_tree (tree *tp, walk_tree_fn func, void *data, struct pointer_set_t *pset)
+walk_tree_1 (tree *tp, walk_tree_fn func, void *data,
+ struct pointer_set_t *pset, walk_tree_lh lh)
{
enum tree_code code;
int walk_subtrees;
return NULL_TREE;
}
- result = lang_hooks.tree_inlining.walk_subtrees (tp, &walk_subtrees, func,
- data, pset);
- if (result || !walk_subtrees)
- return result;
+ if (lh)
+ {
+ result = (*lh) (tp, &walk_subtrees, func, data, pset);
+ if (result || !walk_subtrees)
+ return result;
+ }
switch (code)
{
case IDENTIFIER_NODE:
case INTEGER_CST:
case REAL_CST:
+ case FIXED_CST:
case VECTOR_CST:
case STRING_CST:
case BLOCK:
case OMP_CLAUSE_PRIVATE:
case OMP_CLAUSE_SHARED:
case OMP_CLAUSE_FIRSTPRIVATE:
- case OMP_CLAUSE_LASTPRIVATE:
case OMP_CLAUSE_COPYIN:
case OMP_CLAUSE_COPYPRIVATE:
case OMP_CLAUSE_IF:
case OMP_CLAUSE_NOWAIT:
case OMP_CLAUSE_ORDERED:
case OMP_CLAUSE_DEFAULT:
+ case OMP_CLAUSE_UNTIED:
+ WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
+
+ case OMP_CLAUSE_LASTPRIVATE:
+ WALK_SUBTREE (OMP_CLAUSE_DECL (*tp));
+ WALK_SUBTREE (OMP_CLAUSE_LASTPRIVATE_STMT (*tp));
WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
+ case OMP_CLAUSE_COLLAPSE:
+ {
+ int i;
+ for (i = 0; i < 3; i++)
+ WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, i));
+ WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
+ }
+
case OMP_CLAUSE_REDUCTION:
{
int i;
WALK_SUBTREE_TAIL (TREE_OPERAND (*tp, len));
}
+ case CHANGE_DYNAMIC_TYPE_EXPR:
+ WALK_SUBTREE (CHANGE_DYNAMIC_TYPE_NEW_TYPE (*tp));
+ WALK_SUBTREE_TAIL (CHANGE_DYNAMIC_TYPE_LOCATION (*tp));
+
case DECL_EXPR:
/* If this is a TYPE_DECL, walk into the fields of the type that it's
defining. We only want to walk into these fields of a type in this
if (result || !walk_subtrees)
return result;
- result = walk_type_fields (*type_p, func, data, pset);
+ result = walk_type_fields (*type_p, func, data, pset, lh);
if (result)
return result;
else if (TREE_CODE (*type_p) == BOOLEAN_TYPE
|| TREE_CODE (*type_p) == ENUMERAL_TYPE
|| TREE_CODE (*type_p) == INTEGER_TYPE
+ || TREE_CODE (*type_p) == FIXED_POINT_TYPE
|| TREE_CODE (*type_p) == REAL_TYPE)
{
WALK_SUBTREE (TYPE_MIN_VALUE (*type_p));
/* FALLTHRU */
default:
- if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
- || IS_GIMPLE_STMT_CODE_CLASS (TREE_CODE_CLASS (code)))
+ if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)))
{
int i, len;
if (len)
{
for (i = 0; i < len - 1; ++i)
- WALK_SUBTREE (GENERIC_TREE_OPERAND (*tp, i));
- WALK_SUBTREE_TAIL (GENERIC_TREE_OPERAND (*tp, len - 1));
+ WALK_SUBTREE (TREE_OPERAND (*tp, i));
+ WALK_SUBTREE_TAIL (TREE_OPERAND (*tp, len - 1));
}
}
/* If this is a type, walk the needed fields in the type. */
else if (TYPE_P (*tp))
- return walk_type_fields (*tp, func, data, pset);
+ return walk_type_fields (*tp, func, data, pset, lh);
break;
}
/* Like walk_tree, but does not walk duplicate nodes more than once. */
tree
-walk_tree_without_duplicates (tree *tp, walk_tree_fn func, void *data)
+walk_tree_without_duplicates_1 (tree *tp, walk_tree_fn func, void *data,
+ walk_tree_lh lh)
{
tree result;
struct pointer_set_t *pset;
pset = pointer_set_create ();
- result = walk_tree (tp, func, data, pset);
+ result = walk_tree_1 (tp, func, data, pset, lh);
pointer_set_destroy (pset);
return result;
}
-/* Return true if STMT is an empty statement or contains nothing but
- empty statements. */
-
-bool
-empty_body_p (tree stmt)
-{
- tree_stmt_iterator i;
- tree body;
-
- if (IS_EMPTY_STMT (stmt))
- return true;
- else if (TREE_CODE (stmt) == BIND_EXPR)
- body = BIND_EXPR_BODY (stmt);
- else if (TREE_CODE (stmt) == STATEMENT_LIST)
- body = stmt;
- else
- return false;
-
- for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i))
- if (!empty_body_p (tsi_stmt (i)))
- return false;
-
- return true;
-}
-
tree *
tree_block (tree t)
{
if (IS_EXPR_CODE_CLASS (c))
return &t->exp.block;
- else if (IS_GIMPLE_STMT_CODE_CLASS (c))
- return &GIMPLE_STMT_BLOCK (t);
gcc_unreachable ();
return NULL;
}
-tree *
-generic_tree_operand (tree node, int i)
-{
- if (GIMPLE_STMT_P (node))
- return &GIMPLE_STMT_OPERAND (node, i);
- return &TREE_OPERAND (node, i);
-}
-
-tree *
-generic_tree_type (tree node)
-{
- if (GIMPLE_STMT_P (node))
- return &void_type_node;
- return &TREE_TYPE (node);
-}
-
/* Build and return a TREE_LIST of arguments in the CALL_EXPR exp.
FIXME: don't use this function. It exists for compatibility with
the old representation of CALL_EXPRs where a list was used to hold the
return arglist;
}
+
+/* Create a nameless artificial label and put it in the current function
+ context. Returns the newly created label. */
+
+tree
+create_artificial_label (void)
+{
+ tree lab = build_decl (LABEL_DECL, NULL_TREE, void_type_node);
+
+ DECL_ARTIFICIAL (lab) = 1;
+ DECL_IGNORED_P (lab) = 1;
+ DECL_CONTEXT (lab) = current_function_decl;
+ return lab;
+}
+
+/* Given a tree, try to return a useful variable name that we can use
+ to prefix a temporary that is being assigned the value of the tree.
+ I.E. given <temp> = &A, return A. */
+
+const char *
+get_name (tree t)
+{
+ tree stripped_decl;
+
+ stripped_decl = t;
+ STRIP_NOPS (stripped_decl);
+ if (DECL_P (stripped_decl) && DECL_NAME (stripped_decl))
+ return IDENTIFIER_POINTER (DECL_NAME (stripped_decl));
+ else
+ {
+ switch (TREE_CODE (stripped_decl))
+ {
+ case ADDR_EXPR:
+ return get_name (TREE_OPERAND (stripped_decl, 0));
+ default:
+ return NULL;
+ }
+ }
+}
+
+/* Return true if TYPE has a variable argument list. */
+
+bool
+stdarg_p (tree fntype)
+{
+ function_args_iterator args_iter;
+ tree n = NULL_TREE, t;
+
+ if (!fntype)
+ return false;
+
+ FOREACH_FUNCTION_ARGS(fntype, t, args_iter)
+ {
+ n = t;
+ }
+
+ return n != NULL_TREE && n != void_type_node;
+}
+
+/* Return true if TYPE has a prototype. */
+
+bool
+prototype_p (tree fntype)
+{
+ tree t;
+
+ gcc_assert (fntype != NULL_TREE);
+
+ t = TYPE_ARG_TYPES (fntype);
+ return (t != NULL_TREE);
+}
+
+/* Return the number of arguments that a function has. */
+
+int
+function_args_count (tree fntype)
+{
+ function_args_iterator args_iter;
+ tree t;
+ int num = 0;
+
+ if (fntype)
+ {
+ FOREACH_FUNCTION_ARGS(fntype, t, args_iter)
+ {
+ num++;
+ }
+ }
+
+ return num;
+}
+
+/* If BLOCK is inlined from an __attribute__((__artificial__))
+ routine, return pointer to location from where it has been
+ called. */
+location_t *
+block_nonartificial_location (tree block)
+{
+ location_t *ret = NULL;
+
+ while (block && TREE_CODE (block) == BLOCK
+ && BLOCK_ABSTRACT_ORIGIN (block))
+ {
+ tree ao = BLOCK_ABSTRACT_ORIGIN (block);
+
+ while (TREE_CODE (ao) == BLOCK && BLOCK_ABSTRACT_ORIGIN (ao))
+ ao = BLOCK_ABSTRACT_ORIGIN (ao);
+
+ if (TREE_CODE (ao) == FUNCTION_DECL)
+ {
+ /* If AO is an artificial inline, point RET to the
+ call site locus at which it has been inlined and continue
+ the loop, in case AO's caller is also an artificial
+ inline. */
+ if (DECL_DECLARED_INLINE_P (ao)
+ && lookup_attribute ("artificial", DECL_ATTRIBUTES (ao)))
+ ret = &BLOCK_SOURCE_LOCATION (block);
+ else
+ break;
+ }
+ else if (TREE_CODE (ao) != BLOCK)
+ break;
+
+ block = BLOCK_SUPERCONTEXT (block);
+ }
+ return ret;
+}
+
+/* These are the hash table functions for the hash table of OPTIMIZATION_NODEq
+ nodes. */
+
+/* Return the hash code code X, an OPTIMIZATION_NODE or TARGET_OPTION code. */
+
+static hashval_t
+cl_option_hash_hash (const void *x)
+{
+ const_tree const t = (const_tree) x;
+ const char *p;
+ size_t i;
+ size_t len = 0;
+ hashval_t hash = 0;
+
+ if (TREE_CODE (t) == OPTIMIZATION_NODE)
+ {
+ p = (const char *)TREE_OPTIMIZATION (t);
+ len = sizeof (struct cl_optimization);
+ }
+
+ else if (TREE_CODE (t) == TARGET_OPTION_NODE)
+ {
+ p = (const char *)TREE_TARGET_OPTION (t);
+ len = sizeof (struct cl_target_option);
+ }
+
+ else
+ gcc_unreachable ();
+
+ /* assume most opt flags are just 0/1, some are 2-3, and a few might be
+ something else. */
+ for (i = 0; i < len; i++)
+ if (p[i])
+ hash = (hash << 4) ^ ((i << 2) | p[i]);
+
+ return hash;
+}
+
+/* Return nonzero if the value represented by *X (an OPTIMIZATION or
+ TARGET_OPTION tree node) is the same as that given by *Y, which is the
+ same. */
+
+static int
+cl_option_hash_eq (const void *x, const void *y)
+{
+ const_tree const xt = (const_tree) x;
+ const_tree const yt = (const_tree) y;
+ const char *xp;
+ const char *yp;
+ size_t len;
+
+ if (TREE_CODE (xt) != TREE_CODE (yt))
+ return 0;
+
+ if (TREE_CODE (xt) == OPTIMIZATION_NODE)
+ {
+ xp = (const char *)TREE_OPTIMIZATION (xt);
+ yp = (const char *)TREE_OPTIMIZATION (yt);
+ len = sizeof (struct cl_optimization);
+ }
+
+ else if (TREE_CODE (xt) == TARGET_OPTION_NODE)
+ {
+ xp = (const char *)TREE_TARGET_OPTION (xt);
+ yp = (const char *)TREE_TARGET_OPTION (yt);
+ len = sizeof (struct cl_target_option);
+ }
+
+ else
+ gcc_unreachable ();
+
+ return (memcmp (xp, yp, len) == 0);
+}
+
+/* Build an OPTIMIZATION_NODE based on the current options. */
+
+tree
+build_optimization_node (void)
+{
+ tree t;
+ void **slot;
+
+ /* Use the cache of optimization nodes. */
+
+ cl_optimization_save (TREE_OPTIMIZATION (cl_optimization_node));
+
+ slot = htab_find_slot (cl_option_hash_table, cl_optimization_node, INSERT);
+ t = (tree) *slot;
+ if (!t)
+ {
+ /* Insert this one into the hash table. */
+ t = cl_optimization_node;
+ *slot = t;
+
+ /* Make a new node for next time round. */
+ cl_optimization_node = make_node (OPTIMIZATION_NODE);
+ }
+
+ return t;
+}
+
+/* Build a TARGET_OPTION_NODE based on the current options. */
+
+tree
+build_target_option_node (void)
+{
+ tree t;
+ void **slot;
+
+ /* Use the cache of optimization nodes. */
+
+ cl_target_option_save (TREE_TARGET_OPTION (cl_target_option_node));
+
+ slot = htab_find_slot (cl_option_hash_table, cl_target_option_node, INSERT);
+ t = (tree) *slot;
+ if (!t)
+ {
+ /* Insert this one into the hash table. */
+ t = cl_target_option_node;
+ *slot = t;
+
+ /* Make a new node for next time round. */
+ cl_target_option_node = make_node (TARGET_OPTION_NODE);
+ }
+
+ return t;
+}
+
#include "gt-tree.h"