/* 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
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
This file is part of GCC.
"unary",
"binary",
"statement",
+ "vl_exp",
"expression",
+ "gimple_stmt"
};
/* obstack.[ch] explicitly declined to prototype this. */
"random kinds",
"lang_decl kinds",
"lang_type kinds",
- "omp clauses"
+ "omp clauses",
+ "gimple statements"
};
#endif /* GATHER_STATISTICS */
static GTY ((if_marked ("tree_map_marked_p"), param_is (struct tree_map)))
htab_t value_expr_for_decl;
-static GTY ((if_marked ("tree_int_map_marked_p"), param_is (struct tree_int_map)))
+static GTY ((if_marked ("tree_priority_map_marked_p"),
+ param_is (struct tree_priority_map)))
htab_t init_priority_for_decl;
static GTY ((if_marked ("tree_map_marked_p"), param_is (struct tree_map)))
htab_t restrict_base_for_decl;
-struct tree_int_map GTY(())
-{
- tree from;
- unsigned short to;
-};
-static unsigned int tree_int_map_hash (const void *);
-static int tree_int_map_eq (const void *, const void *);
-static int tree_int_map_marked_p (const void *);
static void set_type_quals (tree, int);
static int type_hash_eq (const void *, const void *);
static hashval_t type_hash_hash (const void *);
tree global_trees[TI_MAX];
tree integer_types[itk_none];
-unsigned char tree_contains_struct[256][64];
+unsigned char tree_contains_struct[MAX_TREE_CODES][64];
/* Number of operands for each OpenMP clause. */
unsigned const char omp_clause_num_ops[] =
value_expr_for_decl = htab_create_ggc (512, tree_map_hash,
tree_map_eq, 0);
- init_priority_for_decl = htab_create_ggc (512, tree_int_map_hash,
- tree_int_map_eq, 0);
+ init_priority_for_decl = htab_create_ggc (512, tree_priority_map_hash,
+ tree_priority_map_eq, 0);
restrict_base_for_decl = htab_create_ggc (256, tree_map_hash,
tree_map_eq, 0);
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;
tree_contains_struct[FUNCTION_DECL][TS_DECL_WITH_VIS] = 1;
return DECL_WITH_VIS_CHECK (decl)->decl_with_vis.assembler_name;
}
+/* Compare ASMNAME with the DECL_ASSEMBLER_NAME of DECL. */
+
+bool
+decl_assembler_name_equal (tree decl, tree asmname)
+{
+ tree decl_asmname = DECL_ASSEMBLER_NAME (decl);
+
+ if (decl_asmname == asmname)
+ return true;
+
+ /* 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] == '*')
+ {
+ const char *decl_str = IDENTIFIER_POINTER (decl_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 false;
+}
+
/* Compute the number of bytes occupied by a tree with code CODE.
- This function cannot be used for TREE_VEC, PHI_NODE, or STRING_CST
- codes, which are of variable length. */
+ This function cannot be used for nodes that have variable sizes,
+ including TREE_VEC, PHI_NODE, STRING_CST, and CALL_EXPR. */
size_t
tree_code_size (enum tree_code code)
{
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_decl_non_common);
}
case tcc_unary: /* a unary arithmetic expression */
case tcc_binary: /* a binary arithmetic expression */
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 */
}
/* Compute the number of bytes occupied by NODE. This routine only
- looks at TREE_CODE, except for PHI_NODE and TREE_VEC nodes. */
+ looks at TREE_CODE, except for those nodes that have variable sizes. */
size_t
tree_size (tree node)
{
case TREE_VEC:
return (sizeof (struct tree_vec)
- + (TREE_VEC_LENGTH (node) - 1) * sizeof(char *));
+ + (TREE_VEC_LENGTH (node) - 1) * sizeof (tree));
case STRING_CST:
return TREE_STRING_LENGTH (node) + offsetof (struct tree_string, str) + 1;
* sizeof (tree));
default:
- return tree_code_size (code);
+ if (TREE_CODE_CLASS (code) == tcc_vl_exp)
+ return (sizeof (struct tree_exp)
+ + (VL_EXP_OPERAND_LENGTH (node) - 1) * sizeof (tree));
+ else
+ return tree_code_size (code);
}
}
kind = c_kind;
break;
+ case tcc_gimple_stmt:
+ kind = gimple_stmt_kind;
+ break;
+
case tcc_exceptional: /* something random, like an identifier. */
switch (code)
{
TYPE_ALIGN (t) = BITS_PER_UNIT;
TYPE_USER_ALIGN (t) = 0;
TYPE_MAIN_VARIANT (t) = t;
+ TYPE_CANONICAL (t) = t;
/* Default to no attributes for type, but let target change that. */
TYPE_ATTRIBUTES (t) = NULL_TREE;
}
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;
t = ggc_alloc_zone_pass_stat (length, &tree_zone);
memcpy (t, node, length);
- TREE_CHAIN (t) = 0;
+ if (!GIMPLE_TUPLE_P (node))
+ TREE_CHAIN (t) = 0;
TREE_ASM_WRITTEN (t) = 0;
TREE_VISITED (t) = 0;
- t->common.ann = 0;
+ t->base.ann = 0;
if (TREE_CODE_CLASS (code) == tcc_declaration)
{
tree
build_int_cst (tree type, HOST_WIDE_INT low)
{
+ /* Support legacy code. */
+ if (!type)
+ type = integer_type_node;
+
return build_int_cst_wide (type, low, low < 0 ? -1 : 0);
}
tree
build_int_cst_type (tree type, HOST_WIDE_INT low)
{
- unsigned HOST_WIDE_INT val = (unsigned HOST_WIDE_INT) low;
- unsigned HOST_WIDE_INT hi, mask;
- unsigned bits;
- bool signed_p;
- bool negative;
-
- if (!type)
- type = integer_type_node;
+ unsigned HOST_WIDE_INT low1;
+ HOST_WIDE_INT hi;
- bits = TYPE_PRECISION (type);
- signed_p = !TYPE_UNSIGNED (type);
+ gcc_assert (type);
- if (bits >= HOST_BITS_PER_WIDE_INT)
- negative = (low < 0);
- else
- {
- /* If the sign bit is inside precision of LOW, use it to determine
- the sign of the constant. */
- negative = ((val >> (bits - 1)) & 1) != 0;
-
- /* Mask out the bits outside of the precision of the constant. */
- mask = (((unsigned HOST_WIDE_INT) 2) << (bits - 1)) - 1;
-
- if (signed_p && negative)
- val |= ~mask;
- else
- val &= mask;
- }
+ fit_double_type (low, low < 0 ? -1 : 0, &low1, &hi, type);
- /* Determine the high bits. */
- hi = (negative ? ~(unsigned HOST_WIDE_INT) 0 : 0);
+ return build_int_cst_wide (type, low1, hi);
+}
- /* For unsigned type we need to mask out the bits outside of the type
- precision. */
- if (!signed_p)
- {
- if (bits <= HOST_BITS_PER_WIDE_INT)
- hi = 0;
- else
- {
- bits -= HOST_BITS_PER_WIDE_INT;
- mask = (((unsigned HOST_WIDE_INT) 2) << (bits - 1)) - 1;
- hi &= mask;
- }
- }
+/* Create an INT_CST node of TYPE and value HI:LOW. The value is truncated
+ and sign extended according to the value range of TYPE. */
- return build_int_cst_wide (type, val, hi);
+tree
+build_int_cst_wide_type (tree type,
+ unsigned HOST_WIDE_INT low, HOST_WIDE_INT high)
+{
+ fit_double_type (low, high, &low, &high, type);
+ return build_int_cst_wide (type, low, high);
}
/* These are the hash table functions for the hash table of INTEGER_CST
&& TREE_INT_CST_LOW (xt) == TREE_INT_CST_LOW (yt));
}
-/* Create an INT_CST node of TYPE and value HI:LOW. If TYPE is NULL,
- integer_type_node is used. The returned node is always shared.
- For small integers we use a per-type vector cache, for larger ones
- we use a single hash table. */
+/* Create an INT_CST node of TYPE and value HI:LOW.
+ The returned node is always shared. For small integers we use a
+ per-type vector cache, for larger ones we use a single hash table. */
tree
build_int_cst_wide (tree type, unsigned HOST_WIDE_INT low, HOST_WIDE_INT hi)
int ix = -1;
int limit = 0;
- if (!type)
- type = integer_type_node;
+ gcc_assert (type);
switch (TREE_CODE (type))
{
ix = 0;
}
break;
- default:
+
+ case ENUMERAL_TYPE:
break;
+
+ default:
+ gcc_unreachable ();
}
if (ix >= 0)
build_vector (tree type, tree vals)
{
tree v = make_node (VECTOR_CST);
- int over1 = 0, over2 = 0;
+ int over = 0;
tree link;
TREE_VECTOR_CST_ELTS (v) = vals;
{
tree value = TREE_VALUE (link);
- over1 |= TREE_OVERFLOW (value);
- over2 |= TREE_CONSTANT_OVERFLOW (value);
- }
+ /* Don't crash if we get an address constant. */
+ if (!CONSTANT_CLASS_P (value))
+ continue;
- TREE_OVERFLOW (v) = over1;
- TREE_CONSTANT_OVERFLOW (v) = over2;
+ over |= TREE_OVERFLOW (value);
+ }
+ TREE_OVERFLOW (v) = over;
return v;
}
TREE_TYPE (v) = type;
TREE_REAL_CST_PTR (v) = dp;
- TREE_OVERFLOW (v) = TREE_CONSTANT_OVERFLOW (v) = overflow;
+ TREE_OVERFLOW (v) = overflow;
return v;
}
v = build_real (type, real_value_from_int_cst (type, i));
TREE_OVERFLOW (v) |= overflow;
- TREE_CONSTANT_OVERFLOW (v) |= overflow;
return v;
}
TREE_IMAGPART (t) = imag;
TREE_TYPE (t) = type ? type : build_complex_type (TREE_TYPE (real));
TREE_OVERFLOW (t) = TREE_OVERFLOW (real) | TREE_OVERFLOW (imag);
- TREE_CONSTANT_OVERFLOW (t)
- = TREE_CONSTANT_OVERFLOW (real) | TREE_CONSTANT_OVERFLOW (imag);
return t;
}
return size_zero_node;
}
- if (TREE_CODE (t) == INTEGER_CST)
- t = force_fit_type (t, 0, false, false);
-
return t;
}
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:
case SYMBOL_MEMORY_TAG:
case NAME_MEMORY_TAG:
case STRUCT_FIELD_TAG:
+ case MEMORY_PARTITION_TAG:
return TS_MEMORY_TAG;
default:
return TS_DECL_NON_COMMON;
case tcc_binary:
case tcc_expression:
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;
}
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;
|| CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 1))
|| CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 2)));
- case CALL_EXPR:
- return CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 1));
-
default:
break;
}
return 0;
}
+ case tcc_vl_exp:
+ switch (code)
+ {
+ case CALL_EXPR:
+ {
+ tree arg;
+ call_expr_arg_iterator iter;
+ FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
+ if (CONTAINS_PLACEHOLDER_P (arg))
+ return 1;
+ return 0;
+ }
+ default:
+ return 0;
+ }
+
default:
return 0;
}
}
break;
+ case tcc_vl_exp:
+ {
+ tree copy = NULL_TREE;
+ int i;
+ int n = TREE_OPERAND_LENGTH (exp);
+ for (i = 1; i < n; i++)
+ {
+ tree op = TREE_OPERAND (exp, i);
+ tree newop = SUBSTITUTE_IN_EXPR (op, f, r);
+ if (newop != op)
+ {
+ copy = copy_node (exp);
+ TREE_OPERAND (copy, i) = newop;
+ }
+ }
+ if (copy)
+ new = fold (copy);
+ else
+ return exp;
+ }
+
default:
gcc_unreachable ();
}
: (REFERENCE_CLASS_P (elt)
|| UNARY_CLASS_P (elt)
|| BINARY_CLASS_P (elt)
+ || VL_EXP_CLASS_P (elt)
|| EXPRESSION_CLASS_P (elt))
? TREE_OPERAND (elt, 0) : 0))
if (TYPE_MAIN_VARIANT (TREE_TYPE (elt)) == need_type)
: (REFERENCE_CLASS_P (elt)
|| UNARY_CLASS_P (elt)
|| BINARY_CLASS_P (elt)
+ || VL_EXP_CLASS_P (elt)
|| EXPRESSION_CLASS_P (elt))
? TREE_OPERAND (elt, 0) : 0))
if (POINTER_TYPE_P (TREE_TYPE (elt))
}
break;
+ case tcc_vl_exp:
+ {
+ tree copy = NULL_TREE;
+ int i;
+ int n = TREE_OPERAND_LENGTH (exp);
+ for (i = 1; i < n; i++)
+ {
+ tree op = TREE_OPERAND (exp, i);
+ tree newop = SUBSTITUTE_PLACEHOLDER_IN_EXPR (op, obj);
+ if (newop != op)
+ {
+ if (!copy)
+ copy = copy_node (exp);
+ TREE_OPERAND (copy, i) = newop;
+ }
+ }
+ if (copy)
+ return fold (copy);
+ else
+ return exp;
+ }
+
default:
gcc_unreachable ();
}
case CONVERT_EXPR:
case FLOAT_EXPR:
case FIX_TRUNC_EXPR:
- case FIX_FLOOR_EXPR:
- case FIX_ROUND_EXPR:
- case FIX_CEIL_EXPR:
result = build_nt (code, stabilize_reference (TREE_OPERAND (ref, 0)));
break;
case tcc_statement:
case tcc_expression:
case tcc_reference:
+ case tcc_vl_exp:
/* If the expression has side-effects, then encase it in a SAVE_EXPR
so that it will only be evaluated once. */
/* The reference (r) and comparison (<) classes could be handled as
#else
SET_EXPR_LOCUS (t, NULL);
#endif
- TREE_COMPLEXITY (t) = 0;
TREE_OPERAND (t, 0) = node;
TREE_BLOCK (t) = NULL_TREE;
if (node && !TYPE_P (node))
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
+
t = make_node_stat (code PASS_MEM_STAT);
TREE_TYPE (t) = tt;
return t;
}
+
+/* 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)
tree t;
gcc_assert (TREE_CODE_LENGTH (code) == 3);
+ gcc_assert (TREE_CODE_CLASS (code) != tcc_vl_exp);
t = make_node_stat (code PASS_MEM_STAT);
TREE_TYPE (t) = tt;
- side_effects = TREE_SIDE_EFFECTS (t);
+ /* As a special exception, if COND_EXPR has NULL branches, we
+ assume that it is a gimple statement and always consider
+ it to have side effects. */
+ if (code == COND_EXPR
+ && tt == void_type_node
+ && arg1 == NULL_TREE
+ && arg2 == NULL_TREE)
+ side_effects = true;
+ else
+ side_effects = TREE_SIDE_EFFECTS (t);
PROCESS_ARG(0);
PROCESS_ARG(1);
PROCESS_ARG(2);
- if (code == CALL_EXPR && !side_effects)
- {
- tree node;
- int i;
-
- /* Calls have side-effects, except those to const or
- pure functions. */
- i = call_expr_flags (t);
- if (!(i & (ECF_CONST | ECF_PURE)))
- side_effects = 1;
-
- /* And even those have side-effects if their arguments do. */
- else for (node = arg1; node; node = TREE_CHAIN (node))
- if (TREE_SIDE_EFFECTS (TREE_VALUE (node)))
- {
- side_effects = 1;
- break;
- }
- }
-
TREE_SIDE_EFFECTS (t) = side_effects;
TREE_THIS_VOLATILE (t)
= (TREE_CODE_CLASS (code) == tcc_reference
int i;
va_list p;
+ gcc_assert (TREE_CODE_CLASS (code) != tcc_vl_exp);
+
va_start (p, code);
t = make_node (code);
va_end (p);
return t;
}
+
+/* Similar to build_nt, but for creating a CALL_EXPR object with
+ ARGLIST passed as a list. */
+
+tree
+build_nt_call_list (tree fn, tree arglist)
+{
+ tree t;
+ int i;
+
+ t = build_vl_exp (CALL_EXPR, list_length (arglist) + 3);
+ CALL_EXPR_FN (t) = fn;
+ CALL_EXPR_STATIC_CHAIN (t) = NULL_TREE;
+ for (i = 0; arglist; arglist = TREE_CHAIN (arglist), i++)
+ CALL_EXPR_ARG (t, i) = TREE_VALUE (arglist);
+ return t;
+}
\f
/* Create a DECL_... node of code CODE, name NAME and data type TYPE.
We do NOT enter this node in any sort of symbol table.
expand_location (source_location loc)
{
expanded_location xloc;
- if (loc == 0) { xloc.file = NULL; xloc.line = 0; xloc.column = 0; }
+ if (loc == 0)
+ {
+ xloc.file = NULL;
+ xloc.line = 0;
+ xloc.column = 0;
+ }
else
{
const struct line_map *map = linemap_lookup (&line_table, loc);
}
#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
+ )
+{
+#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;
+ 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
+}
+\f
/* Return a declaration like DDECL except that its DECL_ATTRIBUTES
is ATTRIBUTE. */
TYPE_REFERENCE_TO (ntype) = 0;
TYPE_ATTRIBUTES (ntype) = attribute;
+ if (TYPE_STRUCTURAL_EQUALITY_P (ttype))
+ SET_TYPE_STRUCTURAL_EQUALITY (ntype);
+ else
+ TYPE_CANONICAL (ntype)
+ = build_qualified_type (TYPE_CANONICAL (ttype), quals);
+
/* Create a new main variant of TYPE. */
TYPE_MAIN_VARIANT (ntype) = ntype;
TYPE_NEXT_VARIANT (ntype) = 0;
}
ntype = type_hash_canon (hashcode, ntype);
+
+ /* 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))
+ SET_TYPE_STRUCTURAL_EQUALITY (ntype);
+
ttype = build_qualified_type (ntype, quals);
}
{
t = build_variant_type_copy (type);
set_type_quals (t, type_quals);
+
+ if (TYPE_STRUCTURAL_EQUALITY_P (type))
+ /* Propagate structural equality. */
+ SET_TYPE_STRUCTURAL_EQUALITY (t);
+ else if (TYPE_CANONICAL (type) != type)
+ /* Build the underlying canonical type, since it is different
+ from TYPE. */
+ TYPE_CANONICAL (t) = build_qualified_type (TYPE_CANONICAL (type),
+ type_quals);
+ else
+ /* T is its own canonical type. */
+ TYPE_CANONICAL (t) = t;
+
}
return t;
}
/* Create a new distinct copy of TYPE. The new type is made its own
- MAIN_VARIANT. */
+ MAIN_VARIANT. If TYPE requires structural equality checks, the
+ resulting type requires structural equality checks; otherwise, its
+ TYPE_CANONICAL points to itself. */
tree
build_distinct_type_copy (tree type)
TYPE_POINTER_TO (t) = 0;
TYPE_REFERENCE_TO (t) = 0;
+ /* Set the canonical type either to a new equivalence class, or
+ propagate the need for structural equality checks. */
+ if (TYPE_STRUCTURAL_EQUALITY_P (type))
+ SET_TYPE_STRUCTURAL_EQUALITY (t);
+ else
+ TYPE_CANONICAL (t) = t;
+
/* Make it its own variant. */
TYPE_MAIN_VARIANT (t) = t;
TYPE_NEXT_VARIANT (t) = 0;
+ /* VRP assumes that TREE_TYPE (TYPE_MIN_VALUE (type)) == type. */
+ if (INTEGRAL_TYPE_P (t) || SCALAR_FLOAT_TYPE_P (t))
+ {
+ if (TYPE_MIN_VALUE (t) != NULL_TREE)
+ TYPE_MIN_VALUE (t) = fold_convert (t, TYPE_MIN_VALUE (t));
+ if (TYPE_MAX_VALUE (t) != NULL_TREE)
+ TYPE_MAX_VALUE (t) = fold_convert (t, TYPE_MAX_VALUE (t));
+ }
+
return t;
}
-/* Create a new variant of TYPE, equivalent but distinct.
- This is so the caller can modify it. */
+/* Create a new variant of TYPE, equivalent but distinct. This is so
+ the caller can modify it. TYPE_CANONICAL for the return type will
+ be equivalent to TYPE_CANONICAL of TYPE, indicating that the types
+ are considered equal by the language itself (or that both types
+ require structural equality checks). */
tree
build_variant_type_copy (tree type)
tree t, m = TYPE_MAIN_VARIANT (type);
t = build_distinct_type_copy (type);
+
+ /* Since we're building a variant, assume that it is a non-semantic
+ variant. This also propagates TYPE_STRUCTURAL_EQUALITY_P. */
+ TYPE_CANONICAL (t) = TYPE_CANONICAL (type);
/* Add the new type to the chain of variants of TYPE. */
TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m);
/* Return true if the from tree in both tree maps are equal. */
int
-tree_map_eq (const void *va, const void *vb)
+tree_map_base_eq (const void *va, const void *vb)
{
- const struct tree_map *a = va, *b = vb;
+ const struct tree_map_base *a = va, *b = vb;
return (a->from == b->from);
}
/* Hash a from tree in a tree_map. */
unsigned int
-tree_map_hash (const void *item)
+tree_map_base_hash (const void *item)
{
- return (((const struct tree_map *) item)->hash);
+ return htab_hash_pointer (((const struct tree_map_base *)item)->from);
}
/* Return true if this tree map structure is marked for garbage collection
structure goes away when the from tree goes away. */
int
-tree_map_marked_p (const void *p)
+tree_map_base_marked_p (const void *p)
{
- tree from = ((struct tree_map *) p)->from;
+ return ggc_marked_p (((struct tree_map_base *) p)->from);
+}
- return ggc_marked_p (from);
+unsigned int
+tree_map_hash (const void *item)
+{
+ return (((const struct tree_map *) item)->hash);
}
-/* Return true if the trees in the tree_int_map *'s VA and VB are equal. */
+/* Return the initialization priority for DECL. */
-static int
-tree_int_map_eq (const void *va, const void *vb)
+priority_type
+decl_init_priority_lookup (tree decl)
{
- const struct tree_int_map *a = va, *b = vb;
- return (a->from == b->from);
+ struct tree_priority_map *h;
+ 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);
+ return h ? h->init : DEFAULT_INIT_PRIORITY;
}
-/* Hash a from tree in the tree_int_map * ITEM. */
+/* Return the finalization priority for DECL. */
-static unsigned int
-tree_int_map_hash (const void *item)
+priority_type
+decl_fini_priority_lookup (tree decl)
{
- return htab_hash_pointer (((const struct tree_int_map *)item)->from);
+ struct tree_priority_map *h;
+ 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);
+ return h ? h->fini : DEFAULT_INIT_PRIORITY;
}
-/* Return true if this tree int map structure is marked for garbage collection
- purposes. We simply return true if the from tree_int_map *P's from tree is marked, so that this
- structure goes away when the from tree goes away. */
+/* Return the initialization and finalization priority information for
+ DECL. If there is no previous priority information, a freshly
+ allocated structure is returned. */
-static int
-tree_int_map_marked_p (const void *p)
+static struct tree_priority_map *
+decl_priority_info (tree decl)
{
- tree from = ((struct tree_int_map *) p)->from;
+ struct tree_priority_map in;
+ struct tree_priority_map *h;
+ void **loc;
- return ggc_marked_p (from);
+ in.base.from = decl;
+ loc = htab_find_slot (init_priority_for_decl, &in, INSERT);
+ h = *loc;
+ if (!h)
+ {
+ h = GGC_CNEW (struct tree_priority_map);
+ *loc = h;
+ h->base.from = decl;
+ h->init = DEFAULT_INIT_PRIORITY;
+ h->fini = DEFAULT_INIT_PRIORITY;
+ }
+
+ return h;
}
-/* Lookup an init priority for FROM, and return it if we find one. */
-unsigned short
-decl_init_priority_lookup (tree from)
+/* Set the initialization priority for DECL to PRIORITY. */
+
+void
+decl_init_priority_insert (tree decl, priority_type priority)
{
- struct tree_int_map *h, in;
- in.from = from;
+ struct tree_priority_map *h;
- h = htab_find_with_hash (init_priority_for_decl,
- &in, htab_hash_pointer (from));
- if (h)
- return h->to;
- return 0;
-}
+ gcc_assert (VAR_OR_FUNCTION_DECL_P (decl));
+ h = decl_priority_info (decl);
+ h->init = priority;
+}
-/* Insert a mapping FROM->TO in the init priority hashtable. */
+/* Set the finalization priority for DECL to PRIORITY. */
void
-decl_init_priority_insert (tree from, unsigned short to)
+decl_fini_priority_insert (tree decl, priority_type priority)
{
- struct tree_int_map *h;
- void **loc;
+ struct tree_priority_map *h;
- h = ggc_alloc (sizeof (struct tree_int_map));
- h->from = from;
- h->to = to;
- loc = htab_find_slot_with_hash (init_priority_for_decl, h,
- htab_hash_pointer (from), INSERT);
- *(struct tree_int_map **) loc = h;
+ gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
+ h = decl_priority_info (decl);
+ h->fini = priority;
}
/* Look up a restrict qualified base decl for FROM. */
struct tree_map *h;
struct tree_map in;
- in.from = from;
+ in.base.from = from;
h = htab_find_with_hash (restrict_base_for_decl, &in,
htab_hash_pointer (from));
return h ? h->to : NULL_TREE;
h = ggc_alloc (sizeof (struct tree_map));
h->hash = htab_hash_pointer (from);
- h->from = from;
+ h->base.from = from;
h->to = to;
loc = htab_find_slot_with_hash (restrict_base_for_decl, h, h->hash, INSERT);
*(struct tree_map **) loc = h;
decl_debug_expr_lookup (tree from)
{
struct tree_map *h, in;
- in.from = from;
+ in.base.from = from;
h = htab_find_with_hash (debug_expr_for_decl, &in, htab_hash_pointer (from));
if (h)
h = ggc_alloc (sizeof (struct tree_map));
h->hash = htab_hash_pointer (from);
- h->from = from;
+ h->base.from = from;
h->to = to;
loc = htab_find_slot_with_hash (debug_expr_for_decl, h, h->hash, INSERT);
*(struct tree_map **) loc = h;
decl_value_expr_lookup (tree from)
{
struct tree_map *h, in;
- in.from = from;
+ in.base.from = from;
h = htab_find_with_hash (value_expr_for_decl, &in, htab_hash_pointer (from));
if (h)
h = ggc_alloc (sizeof (struct tree_map));
h->hash = htab_hash_pointer (from);
- h->from = from;
+ h->base.from = from;
h->to = to;
loc = htab_find_slot_with_hash (value_expr_for_decl, h, h->hash, INSERT);
*(struct tree_map **) loc = h;
return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
case CALL_EXPR:
- cmp = simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+ cmp = simple_cst_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2));
if (cmp <= 0)
return cmp;
- return
- simple_cst_list_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
+ 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);
+ arg1 && arg2;
+ arg1 = next_call_expr_arg (&iter1),
+ arg2 = next_call_expr_arg (&iter2))
+ {
+ cmp = simple_cst_equal (arg1, arg2);
+ if (cmp <= 0)
+ return cmp;
+ }
+ return arg1 == arg2;
+ }
case TARGET_EXPR:
/* Special case: if either target is an unallocated VAR_DECL,
val = iterative_hash_hashval_t (two, val);
}
else
- for (i = TREE_CODE_LENGTH (code) - 1; i >= 0; --i)
+ for (i = TREE_OPERAND_LENGTH (t) - 1; i >= 0; --i)
val = iterative_hash_expr (TREE_OPERAND (t, i), val);
}
return val;
TYPE_NEXT_PTR_TO (t) = TYPE_POINTER_TO (to_type);
TYPE_POINTER_TO (to_type) = t;
+ if (TYPE_STRUCTURAL_EQUALITY_P (to_type))
+ SET_TYPE_STRUCTURAL_EQUALITY (t);
+ else if (TYPE_CANONICAL (to_type) != to_type)
+ TYPE_CANONICAL (t)
+ = build_pointer_type_for_mode (TYPE_CANONICAL (to_type),
+ mode, can_alias_all);
+
/* Lay out the type. This function has many callers that are concerned
with expression-construction, and this simplifies them all. */
layout_type (t);
TYPE_NEXT_REF_TO (t) = TYPE_REFERENCE_TO (to_type);
TYPE_REFERENCE_TO (to_type) = t;
+ if (TYPE_STRUCTURAL_EQUALITY_P (to_type))
+ SET_TYPE_STRUCTURAL_EQUALITY (t);
+ else if (TYPE_CANONICAL (to_type) != to_type)
+ TYPE_CANONICAL (t)
+ = build_reference_type_for_mode (TYPE_CANONICAL (to_type),
+ mode, can_alias_all);
+
layout_type (t);
return t;
if (host_integerp (maxval, 1))
return type_hash_canon (tree_low_cst (maxval, 1), itype);
else
- return itype;
+ {
+ /* Since we cannot hash this type, we need to compare it using
+ structural equality checks. */
+ SET_TYPE_STRUCTURAL_EQUALITY (itype);
+ return itype;
+ }
}
/* Builds a signed or unsigned integer type of precision PRECISION.
t = type_hash_canon (hashcode, t);
if (save == t)
layout_type (t);
+
+ if (TYPE_CANONICAL (t) == t)
+ {
+ if (TYPE_STRUCTURAL_EQUALITY_P (elt_type))
+ SET_TYPE_STRUCTURAL_EQUALITY (t);
+ else if (TYPE_CANONICAL (elt_type) != elt_type)
+ TYPE_CANONICAL (t)
+ = build_array_type (TYPE_CANONICAL (elt_type), index_type);
+ }
+
return t;
}
if (!COMPLETE_TYPE_P (t))
layout_type (t);
+
+ if (TYPE_CANONICAL (t) == t)
+ {
+ if (TYPE_STRUCTURAL_EQUALITY_P (elt_type)
+ || TYPE_STRUCTURAL_EQUALITY_P (index_type))
+ SET_TYPE_STRUCTURAL_EQUALITY (t);
+ else if (TYPE_CANONICAL (elt_type) != elt_type
+ || TYPE_CANONICAL (index_type) != index_type)
+ TYPE_CANONICAL (t)
+ = build_array_type (TYPE_CANONICAL (elt_type),
+ TYPE_CANONICAL (index_type));
+ }
+
return t;
}
TREE_TYPE (t) = value_type;
TYPE_ARG_TYPES (t) = arg_types;
+ /* We don't have canonicalization of function types, yet. */
+ SET_TYPE_STRUCTURAL_EQUALITY (t);
+
/* If we already have such a type, use the old one. */
hashcode = iterative_hash_object (TYPE_HASH (value_type), hashcode);
hashcode = type_hash_list (arg_types, hashcode);
argtypes = tree_cons (NULL_TREE, ptype, argtypes);
TYPE_ARG_TYPES (t) = argtypes;
+ /* We don't have canonicalization of method types yet. */
+ SET_TYPE_STRUCTURAL_EQUALITY (t);
+
/* If we already have such a type, use the old one. */
hashcode = iterative_hash_object (TYPE_HASH (basetype), hashcode);
hashcode = iterative_hash_object (TYPE_HASH (rettype), hashcode);
if (!COMPLETE_TYPE_P (t))
layout_type (t);
+ if (TYPE_CANONICAL (t) == t)
+ {
+ if (TYPE_STRUCTURAL_EQUALITY_P (basetype)
+ || TYPE_STRUCTURAL_EQUALITY_P (type))
+ SET_TYPE_STRUCTURAL_EQUALITY (t);
+ else if (TYPE_CANONICAL (basetype) != basetype
+ || TYPE_CANONICAL (type) != type)
+ TYPE_CANONICAL (t)
+ = build_offset_type (TYPE_CANONICAL (basetype),
+ TYPE_CANONICAL (type));
+ }
+
return t;
}
if (!COMPLETE_TYPE_P (t))
layout_type (t);
+ if (TYPE_CANONICAL (t) == t)
+ {
+ if (TYPE_STRUCTURAL_EQUALITY_P (component_type))
+ SET_TYPE_STRUCTURAL_EQUALITY (t);
+ else if (TYPE_CANONICAL (component_type) != component_type)
+ TYPE_CANONICAL (t)
+ = 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)
name = 0;
if (name != 0)
- TYPE_NAME (t) = get_identifier (name);
+ TYPE_NAME (t) = build_decl (TYPE_DECL, get_identifier (name), t);
}
return build_qualified_type (t, TYPE_QUALS (component_type));
{
if (first)
uns = DECL_UNSIGNED (TREE_OPERAND (op, 1));
- 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);
+ win = fold_convert (type, op);
}
}
+
*unsignedp_ptr = uns;
return win;
}
tree type_low_bound = TYPE_MIN_VALUE (type);
tree type_high_bound = TYPE_MAX_VALUE (type);
bool ok_for_low_bound, ok_for_high_bound;
- tree tmp;
+ unsigned HOST_WIDE_INT low;
+ HOST_WIDE_INT high;
/* If at least one bound of the type is a constant integer, we can check
ourselves and maybe make a decision. If no such decision is possible, but
this type is a subtype, try checking against that. Otherwise, use
- force_fit_type, which checks against the precision.
+ fit_double_type, which checks against the precision.
Compute the status for each possibly constant bound, and return if we see
one does not match. Use ok_for_xxx_bound for this purpose, assigning -1
&& TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (type)))
return int_fits_type_p (c, TREE_TYPE (type));
- /* Or to force_fit_type, if nothing else. */
- tmp = copy_node (c);
- TREE_TYPE (tmp) = type;
- tmp = force_fit_type (tmp, -1, false, false);
- return TREE_INT_CST_HIGH (tmp) == TREE_INT_CST_HIGH (c)
- && TREE_INT_CST_LOW (tmp) == TREE_INT_CST_LOW (c);
+ /* Or to fit_double_type, if nothing else. */
+ low = TREE_INT_CST_LOW (c);
+ high = TREE_INT_CST_HIGH (c);
+ return !fit_double_type (low, high, &low, &high, type);
+}
+
+/* Stores bounds of an integer TYPE in MIN and MAX. If TYPE has non-constant
+ bounds or is a POINTER_TYPE, the maximum and/or minimum values that can be
+ represented (assuming two's-complement arithmetic) within the bit
+ precision of the type are returned instead. */
+
+void
+get_type_static_bounds (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)
+ mpz_set_double_int (min, tree_to_double_int (TYPE_MIN_VALUE (type)),
+ TYPE_UNSIGNED (type));
+ else
+ {
+ if (TYPE_UNSIGNED (type))
+ mpz_set_ui (min, 0);
+ else
+ {
+ double_int mn;
+ mn = double_int_mask (TYPE_PRECISION (type) - 1);
+ mn = double_int_sext (double_int_add (mn, double_int_one),
+ TYPE_PRECISION (type));
+ mpz_set_double_int (min, mn, false);
+ }
+ }
+
+ if (!POINTER_TYPE_P (type) && TYPE_MAX_VALUE (type)
+ && TREE_CODE (TYPE_MAX_VALUE (type)) == INTEGER_CST)
+ mpz_set_double_int (max, tree_to_double_int (TYPE_MAX_VALUE (type)),
+ TYPE_UNSIGNED (type));
+ else
+ {
+ if (TYPE_UNSIGNED (type))
+ mpz_set_double_int (max, double_int_mask (TYPE_PRECISION (type)),
+ true);
+ else
+ mpz_set_double_int (max, double_int_mask (TYPE_PRECISION (type) - 1),
+ true);
+ }
}
/* Subprogram of following function. Called by walk_tree.
/* The first operand to the CALL is the address of the function
called. */
- addr = TREE_OPERAND (call, 0);
+ addr = CALL_EXPR_FN (call);
STRIP_NOPS (addr);
*p = '_';
}
-/* Generate a name for a function unique to this translation unit.
+/* Generate a name for a special-purpose function function.
+ The generated name may need to be unique across the whole link.
TYPE is some string to identify the purpose of this function to the
- linker or collect2. */
+ linker or collect2; it must start with an uppercase letter,
+ one of:
+ I - for constructors
+ D - for destructors
+ N - for C++ anonymous namespaces
+ F - for DWARF unwind frame information. */
tree
-get_file_function_name_long (const char *type)
+get_file_function_name (const char *type)
{
char *buf;
const char *p;
char *q;
+ /* If we already have a name we know to be unique, just use that. */
if (first_global_object_name)
+ p = 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)
{
- p = first_global_object_name;
-
- /* For type 'F', the generated name must be unique not only to this
- translation unit but also to any given link. Since global names
- can be overloaded, we concatenate the first global object name
- with a string derived from the file name of this object. */
- if (!strcmp (type, "F"))
- {
- const char *file = main_input_filename;
-
- if (! file)
- file = input_filename;
-
- q = alloca (strlen (p) + 10);
- sprintf (q, "%s_%08X", p, crc32_string (0, file));
-
- p = q;
- }
+ 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);
+ clean_symbol_name (q);
}
else
{
- /* We don't have anything that we know to be unique to this translation
+ /* Otherwise, the name must be unique across the entire link.
+ We don't have anything that we know to be unique to this translation
unit, so use what we do have and throw in some randomness. */
unsigned len;
const char *name = weak_global_object_name;
clean_symbol_name (q);
sprintf (q + len, "_%08X_%08X", crc32_string (0, name),
- crc32_string (0, flag_random_seed));
+ crc32_string (0, get_random_seed (false)));
p = q;
}
return get_identifier (buf);
}
-
-/* If KIND=='I', return a suitable global initializer (constructor) name.
- If KIND=='D', return a suitable global clean-up (destructor) name. */
-
-tree
-get_file_function_name (int kind)
-{
- char p[2];
-
- p[0] = kind;
- p[1] = 0;
-
- return get_file_function_name_long (p);
-}
\f
#if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007)
const char *function)
{
internal_error
- ("tree check: expected tree that contains %qs structure, have %qs in %s, at %s:%d",
+ ("tree check: expected tree that contains %qs structure, have %qs in %s, at %s:%d",
TS_ENUM_NAME(en),
tree_code_name[TREE_CODE (node)], function, trim_filename (file), line);
}
}
/* Similar to above, except that the check is for the bounds of the operand
- vector of an expression node. */
+ vector of an expression node EXP. */
void
-tree_operand_check_failed (int idx, enum tree_code code, const char *file,
+tree_operand_check_failed (int idx, tree exp, const char *file,
int line, const char *function)
{
+ int code = TREE_CODE (exp);
internal_error
("tree check: accessed operand %d of %s with %d operands in %s, at %s:%d",
- idx + 1, tree_code_name[code], TREE_CODE_LENGTH (code),
+ idx + 1, tree_code_name[code], TREE_OPERAND_LENGTH (exp),
function, trim_filename (file), line);
}
TYPE_READONLY (t) = TYPE_READONLY (innertype);
TYPE_VOLATILE (t) = TYPE_VOLATILE (innertype);
+ if (TYPE_STRUCTURAL_EQUALITY_P (innertype))
+ SET_TYPE_STRUCTURAL_EQUALITY (t);
+ else if (TYPE_CANONICAL (innertype) != innertype
+ || mode != VOIDmode)
+ TYPE_CANONICAL (t)
+ = make_vector_type (TYPE_CANONICAL (innertype), nunits, VOIDmode);
+
layout_type (t);
{
long_double_ptr_type_node = build_pointer_type (long_double_type_node);
integer_ptr_type_node = build_pointer_type (integer_type_node);
+ /* Fixed size integer types. */
+ uint32_type_node = build_nonstandard_integer_type (32, true);
+ uint64_type_node = build_nonstandard_integer_type (64, true);
+
/* Decimal float types. */
dfloat32_type_node = make_node (REAL_TYPE);
TYPE_PRECISION (dfloat32_type_node) = DECIMAL32_TYPE_SIZE;
TYPE_MODE (dfloat128_type_node) = TDmode;
dfloat128_ptr_type_node = build_pointer_type (dfloat128_type_node);
- complex_integer_type_node = make_node (COMPLEX_TYPE);
- TREE_TYPE (complex_integer_type_node) = integer_type_node;
- layout_type (complex_integer_type_node);
-
- complex_float_type_node = make_node (COMPLEX_TYPE);
- TREE_TYPE (complex_float_type_node) = float_type_node;
- layout_type (complex_float_type_node);
-
- complex_double_type_node = make_node (COMPLEX_TYPE);
- TREE_TYPE (complex_double_type_node) = double_type_node;
- layout_type (complex_double_type_node);
-
- complex_long_double_type_node = make_node (COMPLEX_TYPE);
- TREE_TYPE (complex_long_double_type_node) = long_double_type_node;
- layout_type (complex_long_double_type_node);
+ complex_integer_type_node = build_complex_type (integer_type_node);
+ complex_float_type_node = build_complex_type (float_type_node);
+ complex_double_type_node = build_complex_type (double_type_node);
+ complex_long_double_type_node = build_complex_type (long_double_type_node);
{
tree t = targetm.build_builtin_va_list ();
declare the type to be __builtin_va_list. */
if (TREE_CODE (t) != RECORD_TYPE)
t = build_variant_type_copy (t);
-
+
va_list_type_node = t;
}
}
reconstruct_complex_type (tree type, tree bottom)
{
tree inner, outer;
-
- if (POINTER_TYPE_P (type))
+
+ if (TREE_CODE (type) == POINTER_TYPE)
+ {
+ inner = reconstruct_complex_type (TREE_TYPE (type), bottom);
+ outer = build_pointer_type_for_mode (inner, TYPE_MODE (type),
+ TYPE_REF_CAN_ALIAS_ALL (type));
+ }
+ else if (TREE_CODE (type) == REFERENCE_TYPE)
{
inner = reconstruct_complex_type (TREE_TYPE (type), bottom);
- outer = build_pointer_type (inner);
+ outer = build_reference_type_for_mode (inner, TYPE_MODE (type),
+ TYPE_REF_CAN_ALIAS_ALL (type));
}
else if (TREE_CODE (type) == ARRAY_TYPE)
{
return t;
}
+/* Set various status flags when building a CALL_EXPR object T. */
+
+static void
+process_call_operands (tree t)
+{
+ bool side_effects;
+
+ side_effects = TREE_SIDE_EFFECTS (t);
+ if (!side_effects)
+ {
+ int i, n;
+ n = TREE_OPERAND_LENGTH (t);
+ for (i = 1; i < n; i++)
+ {
+ tree op = TREE_OPERAND (t, i);
+ if (op && TREE_SIDE_EFFECTS (op))
+ {
+ side_effects = 1;
+ break;
+ }
+ }
+ }
+ if (!side_effects)
+ {
+ int i;
+
+ /* Calls have side-effects, except those to const or
+ pure functions. */
+ i = call_expr_flags (t);
+ if (!(i & (ECF_CONST | ECF_PURE)))
+ side_effects = 1;
+ }
+ TREE_SIDE_EFFECTS (t) = side_effects;
+}
+
+/* Build a tcc_vl_exp object with code CODE and room for LEN operands. LEN
+ includes the implicit operand count in TREE_OPERAND 0, and so must be >= 1.
+ Except for the CODE and operand count field, other storage for the
+ object is initialized to zeros. */
+
+tree
+build_vl_exp_stat (enum tree_code code, int len MEM_STAT_DECL)
+{
+ tree t;
+ int length = (len - 1) * sizeof (tree) + sizeof (struct tree_exp);
+
+ 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
+
+ t = ggc_alloc_zone_pass_stat (length, &tree_zone);
+
+ memset (t, 0, length);
+
+ TREE_SET_CODE (t, code);
+
+ /* Can't use TREE_OPERAND to store the length because if checking is
+ enabled, it will try to check the length before we store it. :-P */
+ t->exp.operands[0] = build_int_cst (sizetype, len);
+
+ return t;
+}
+
+
+/* Build a CALL_EXPR of class tcc_vl_exp with the indicated RETURN_TYPE
+ and FN and a null static chain slot. ARGLIST is a TREE_LIST of the
+ arguments. */
+
+tree
+build_call_list (tree return_type, tree fn, tree arglist)
+{
+ tree t;
+ int i;
+
+ t = build_vl_exp (CALL_EXPR, list_length (arglist) + 3);
+ TREE_TYPE (t) = return_type;
+ CALL_EXPR_FN (t) = fn;
+ CALL_EXPR_STATIC_CHAIN (t) = NULL_TREE;
+ for (i = 0; arglist; arglist = TREE_CHAIN (arglist), i++)
+ CALL_EXPR_ARG (t, i) = TREE_VALUE (arglist);
+ process_call_operands (t);
+ 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
+build_call_nary (tree return_type, tree fn, int nargs, ...)
+{
+ tree ret;
+ va_list args;
+ va_start (args, nargs);
+ ret = build_call_valist (return_type, fn, nargs, args);
+ va_end (args);
+ return ret;
+}
+
+/* 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 a va_list ARGS. */
+
+tree
+build_call_valist (tree return_type, tree fn, int nargs, va_list args)
+{
+ 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;
+ for (i = 0; i < nargs; i++)
+ CALL_EXPR_ARG (t, i) = va_arg (args, tree);
+ process_call_operands (t);
+ 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 a tree array ARGS. */
+
+tree
+build_call_array (tree return_type, tree fn, int nargs, tree *args)
+{
+ 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;
+ for (i = 0; i < nargs; i++)
+ CALL_EXPR_ARG (t, i) = args[i];
+ process_call_operands (t);
+ return t;
+}
+
/* Returns true if it is possible to prove that the index of
an array access REF (an ARRAY_REF expression) falls into the
return true;
}
-/* Return true if T (assumed to be a DECL) is a global variable. */
-
-bool
-is_global_var (tree t)
-{
- if (MTAG_P (t))
- return (TREE_STATIC (t) || MTAG_GLOBAL (t));
- else
- return (TREE_STATIC (t) || DECL_EXTERNAL (t));
-}
-
/* Return true if T (assumed to be a DECL) must be assigned a memory
location. */
bool
needs_to_live_in_memory (tree t)
{
+ if (TREE_CODE (t) == SSA_NAME)
+ t = SSA_NAME_VAR (t);
+
return (TREE_ADDRESSABLE (t)
|| is_global_var (t)
|| (TREE_CODE (t) == RESULT_DECL
return val;
}
-/* Returns the greatest common divisor of A and B, which must be
- INTEGER_CSTs. */
-
-tree
-tree_fold_gcd (tree a, tree b)
-{
- tree a_mod_b;
- tree type = TREE_TYPE (a);
-
- gcc_assert (TREE_CODE (a) == INTEGER_CST);
- gcc_assert (TREE_CODE (b) == INTEGER_CST);
-
- if (integer_zerop (a))
- return b;
-
- if (integer_zerop (b))
- return a;
-
- if (tree_int_cst_sgn (a) == -1)
- a = fold_build2 (MULT_EXPR, type, a,
- build_int_cst (type, -1));
-
- if (tree_int_cst_sgn (b) == -1)
- b = fold_build2 (MULT_EXPR, type, b,
- build_int_cst (type, -1));
-
- while (1)
- {
- a_mod_b = fold_build2 (FLOOR_MOD_EXPR, type, a, b);
-
- if (!TREE_INT_CST_LOW (a_mod_b)
- && !TREE_INT_CST_HIGH (a_mod_b))
- return b;
-
- a = b;
- b = a_mod_b;
- }
-}
/* Returns unsigned variant of TYPE. */
break;
case ARRAY_TYPE:
- /* Don't follow this nodes's type if a pointer for fear that we'll
- have infinite recursion. Those types are uninteresting anyway. */
- if (!POINTER_TYPE_P (TREE_TYPE (type))
- && TREE_CODE (TREE_TYPE (type)) != OFFSET_TYPE)
+ /* Don't follow this nodes's type if a pointer for fear that
+ we'll have infinite recursion. If we have a PSET, then we
+ need not fear. */
+ if (pset
+ || (!POINTER_TYPE_P (TREE_TYPE (type))
+ && TREE_CODE (TREE_TYPE (type)) != OFFSET_TYPE))
WALK_SUBTREE (TREE_TYPE (type));
WALK_SUBTREE (TYPE_DOMAIN (type));
break;
- case BOOLEAN_TYPE:
- case ENUMERAL_TYPE:
- case INTEGER_TYPE:
- case REAL_TYPE:
- WALK_SUBTREE (TYPE_MIN_VALUE (type));
- WALK_SUBTREE (TYPE_MAX_VALUE (type));
- break;
-
case OFFSET_TYPE:
WALK_SUBTREE (TREE_TYPE (type));
WALK_SUBTREE (TYPE_OFFSET_BASETYPE (type));
result = lang_hooks.tree_inlining.walk_subtrees (tp, &walk_subtrees, func,
data, pset);
- if (result || ! walk_subtrees)
+ if (result || !walk_subtrees)
return result;
switch (code)
}
case DECL_EXPR:
- /* Walk into various fields of the type that it's defining. We only
- want to walk into these fields of a type in this case. Note that
- decls get walked as part of the processing of a BIND_EXPR.
-
- ??? Precisely which fields of types that we are supposed to walk in
- this case vs. the normal case aren't well defined. */
- if (TREE_CODE (DECL_EXPR_DECL (*tp)) == TYPE_DECL
- && TREE_CODE (TREE_TYPE (DECL_EXPR_DECL (*tp))) != ERROR_MARK)
+ /* 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
+ case and not in the general case of a mere reference to the type.
+
+ The criterion is as follows: if the field can be an expression, it
+ must be walked only here. This should be in keeping with the fields
+ that are directly gimplified in gimplify_type_sizes in order for the
+ mark/copy-if-shared/unmark machinery of the gimplifier to work with
+ variable-sized types.
+
+ Note that DECLs get walked as part of processing the BIND_EXPR. */
+ if (TREE_CODE (DECL_EXPR_DECL (*tp)) == TYPE_DECL)
{
tree *type_p = &TREE_TYPE (DECL_EXPR_DECL (*tp));
+ if (TREE_CODE (*type_p) == ERROR_MARK)
+ return NULL_TREE;
/* Call the function for the type. See if it returns anything or
doesn't want us to continue. If we are to continue, walk both
the normal fields and those for the declaration case. */
result = (*func) (type_p, &walk_subtrees, data);
if (result || !walk_subtrees)
- return NULL_TREE;
+ return result;
result = walk_type_fields (*type_p, func, data, pset);
if (result)
}
}
+ /* Same for scalar types. */
+ else if (TREE_CODE (*type_p) == BOOLEAN_TYPE
+ || TREE_CODE (*type_p) == ENUMERAL_TYPE
+ || TREE_CODE (*type_p) == INTEGER_TYPE
+ || TREE_CODE (*type_p) == REAL_TYPE)
+ {
+ WALK_SUBTREE (TYPE_MIN_VALUE (*type_p));
+ WALK_SUBTREE (TYPE_MAX_VALUE (*type_p));
+ }
+
WALK_SUBTREE (TYPE_SIZE (*type_p));
WALK_SUBTREE_TAIL (TYPE_SIZE_UNIT (*type_p));
}
/* FALLTHRU */
default:
- if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)))
+ if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
+ || IS_GIMPLE_STMT_CODE_CLASS (TREE_CODE_CLASS (code)))
{
int i, len;
/* Walk over all the sub-trees of this operand. */
- len = TREE_CODE_LENGTH (code);
+ len = TREE_OPERAND_LENGTH (*tp);
/* Go through the subtrees. We need to do this in forward order so
that the scope of a FOR_EXPR is handled properly. */
if (len)
{
for (i = 0; i < len - 1; ++i)
- WALK_SUBTREE (TREE_OPERAND (*tp, i));
- WALK_SUBTREE_TAIL (TREE_OPERAND (*tp, len - 1));
+ WALK_SUBTREE (GENERIC_TREE_OPERAND (*tp, i));
+ WALK_SUBTREE_TAIL (GENERIC_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 true;
}
+tree *
+tree_block (tree t)
+{
+ char const c = TREE_CODE_CLASS (TREE_CODE (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
+ arguments. Places that currently extract the arglist from a CALL_EXPR
+ ought to be rewritten to use the CALL_EXPR itself. */
+tree
+call_expr_arglist (tree exp)
+{
+ tree arglist = NULL_TREE;
+ int i;
+ for (i = call_expr_nargs (exp) - 1; i >= 0; i--)
+ arglist = tree_cons (NULL_TREE, CALL_EXPR_ARG (exp, i), arglist);
+ return arglist;
+}
+
#include "gt-tree.h"