summaryrefslogtreecommitdiff
path: root/gcc/tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree.c')
-rw-r--r--gcc/tree.c316
1 files changed, 278 insertions, 38 deletions
diff --git a/gcc/tree.c b/gcc/tree.c
index ae20c2511e2..842e1d032ca 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -66,7 +66,9 @@ const char *const tree_code_class_strings[] =
"unary",
"binary",
"statement",
+ "vl_exp",
"expression",
+ "gimple_stmt"
};
/* obstack.[ch] explicitly declined to prototype this. */
@@ -337,8 +339,8 @@ decl_assembler_name_equal (tree decl, tree asmname)
}
/* 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)
{
@@ -386,7 +388,7 @@ tree_code_size (enum tree_code code)
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 (char *));
+ + (TREE_CODE_LENGTH (code) - 1) * sizeof (tree));
case tcc_gimple_stmt:
return (sizeof (struct gimple_stmt)
@@ -434,7 +436,7 @@ tree_code_size (enum tree_code code)
}
/* 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)
{
@@ -451,7 +453,7 @@ 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;
@@ -462,7 +464,11 @@ tree_size (tree node)
* 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);
}
}
@@ -2166,6 +2172,7 @@ tree_node_structure (tree t)
case tcc_binary:
case tcc_expression:
case tcc_statement:
+ case tcc_vl_exp:
return TS_EXP;
case tcc_gimple_stmt:
return TS_GIMPLE_STATEMENT;
@@ -2247,9 +2254,6 @@ contains_placeholder_p (tree exp)
|| 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;
}
@@ -2265,6 +2269,22 @@ contains_placeholder_p (tree exp)
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;
}
@@ -2472,6 +2492,27 @@ substitute_in_expr (tree exp, tree f, tree r)
}
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 ();
}
@@ -2503,6 +2544,7 @@ substitute_placeholder_in_expr (tree exp, tree obj)
: (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)
@@ -2515,6 +2557,7 @@ substitute_placeholder_in_expr (tree exp, tree obj)
: (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))
@@ -2602,6 +2645,28 @@ substitute_placeholder_in_expr (tree exp, tree obj)
}
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 ();
}
@@ -2727,6 +2792,7 @@ stabilize_reference_1 (tree e)
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
@@ -3074,6 +3140,7 @@ build3_stat (enum tree_code code, tree tt, tree arg0, tree arg1,
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;
@@ -3084,26 +3151,6 @@ build3_stat (enum tree_code code, tree tt, tree arg0, tree arg1,
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
@@ -3209,6 +3256,8 @@ build_nt (enum tree_code code, ...)
int i;
va_list p;
+ gcc_assert (TREE_CODE_CLASS (code) != tcc_vl_exp);
+
va_start (p, code);
t = make_node (code);
@@ -3220,6 +3269,23 @@ build_nt (enum tree_code 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;
+}
/* 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.
@@ -4916,11 +4982,26 @@ simple_cst_equal (tree t1, tree t2)
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,
@@ -5184,7 +5265,7 @@ iterative_hash_expr (tree t, hashval_t val)
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;
@@ -6246,7 +6327,7 @@ get_callee_fndecl (tree call)
/* 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);
@@ -6665,15 +6746,16 @@ phi_node_elt_check_failed (int idx, int len, const char *file, int 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);
}
@@ -7305,6 +7387,149 @@ build_omp_clause (enum omp_clause_code code)
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
@@ -7988,7 +8213,7 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, struct pointer_set_t *pset)
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. */
@@ -8081,4 +8306,19 @@ generic_tree_type (tree 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"