tree.h (DECL_SEEN_IN_BIND_EXPR_P): New macro.

* tree.h (DECL_SEEN_IN_BIND_EXPR_P): New macro.
	* gimplify.c (gimple_add_tmp_var, gimplify_bind_expr): Use it.
	(gimplify_target_expr, gimplify_expr): Likewise.
	(copy_if_shared_r): No longer need special case for BIND_EXPR.
	(unshare_body, unvisit_body): Only look at nested if BODY_P is
	whole function.
	(gimplify_compound_lval): See if we can strip any useless conversion.
	(gimplify_modify_expr, gimplify_modify_expr_to_memcpy): Take size
	from RHS, not LHS.
	(gimplify_modify_expr_to_memset): Likewise.
	(gimplify_expr, case CONSTRUCTOR): Handle use as statement.
	* tree-inline.c (setup_one_parameter): Use DECL_SEEN_IN_BIND_EXPR_P.
	(declare_inline_vars): Likewise.
	(walk_type_fields): New function.
	(walk_tree): Use it.
	* tree-nested.c (create_tmp_var_for): Show seen in BIND_EXPR.

From-SVN: r84121
This commit is contained in:
Richard Kenner 2004-07-05 16:39:15 +00:00 committed by Richard Kenner
parent 402a3dec96
commit 48eb4e53cd
5 changed files with 193 additions and 137 deletions

View File

@ -5,6 +5,23 @@
2004-07-05 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
* tree.h (DECL_SEEN_IN_BIND_EXPR_P): New macro.
* gimplify.c (gimple_add_tmp_var, gimplify_bind_expr): Use it.
(gimplify_target_expr, gimplify_expr): Likewise.
(copy_if_shared_r): No longer need special case for BIND_EXPR.
(unshare_body, unvisit_body): Only look at nested if BODY_P is
whole function.
(gimplify_compound_lval): See if we can strip any useless conversion.
(gimplify_modify_expr, gimplify_modify_expr_to_memcpy): Take size
from RHS, not LHS.
(gimplify_modify_expr_to_memset): Likewise.
(gimplify_expr, case CONSTRUCTOR): Handle use as statement.
* tree-inline.c (setup_one_parameter): Use DECL_SEEN_IN_BIND_EXPR_P.
(declare_inline_vars): Likewise.
(walk_type_fields): New function.
(walk_tree): Use it.
* tree-nested.c (create_tmp_var_for): Show seen in BIND_EXPR.
* tree-sra.c (struct sra_walk_fns): Init function now returns bool.
(sra_walk_modify_expr): Allow init function to fail.
(scan_init): Now returns bool.

View File

@ -509,20 +509,17 @@ declare_tmp_vars (tree vars, tree scope)
temps = nreverse (last);
TREE_CHAIN (last) = BIND_EXPR_VARS (scope);
BIND_EXPR_VARS (scope) = temps;
/* We don't add the temps to the block for this BIND_EXPR, as we're
not interested in debugging info for them. */
}
}
void
gimple_add_tmp_var (tree tmp)
{
if (TREE_CHAIN (tmp) || tmp->decl.seen_in_bind_expr)
if (TREE_CHAIN (tmp) || DECL_SEEN_IN_BIND_EXPR_P (tmp))
abort ();
DECL_CONTEXT (tmp) = current_function_decl;
tmp->decl.seen_in_bind_expr = 1;
DECL_SEEN_IN_BIND_EXPR_P (tmp) = 1;
if (gimplify_ctxp)
{
@ -657,19 +654,6 @@ copy_if_shared_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
TREE_VISITED (t) = 1;
}
/* Special-case BIND_EXPR. We should never be copying these, therefore
we can omit examining BIND_EXPR_VARS. Which also avoids problems with
double processing of the DECL_INITIAL, which could be seen via both
the BIND_EXPR_VARS and a DECL_EXPR. */
else if (code == BIND_EXPR)
{
if (TREE_VISITED (t))
abort ();
TREE_VISITED (t) = 1;
*walk_subtrees = 0;
walk_tree (&BIND_EXPR_BODY (t), copy_if_shared_r, NULL, NULL);
}
/* If this node has been visited already, unshare it and don't look
any deeper. */
else if (TREE_VISITED (t))
@ -713,8 +697,9 @@ unmark_visited_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
return NULL_TREE;
}
/* Unshare all the trees in BODY_P, a pointer to the body of FNDECL, and the
bodies of any nested functions. */
/* Unshare all the trees in BODY_P, a pointer into the body of FNDECL, and the
bodies of any nested functions if we are unsharing the entire body of
FNDECL. */
static void
unshare_body (tree *body_p, tree fndecl)
@ -722,8 +707,9 @@ unshare_body (tree *body_p, tree fndecl)
struct cgraph_node *cgn = cgraph_node (fndecl);
walk_tree (body_p, copy_if_shared_r, NULL, NULL);
for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
unshare_body (&DECL_SAVED_TREE (cgn->decl), cgn->decl);
if (body_p == &DECL_SAVED_TREE (fndecl))
for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
unshare_body (&DECL_SAVED_TREE (cgn->decl), cgn->decl);
}
/* Likewise, but mark all trees as not visited. */
@ -734,8 +720,9 @@ unvisit_body (tree *body_p, tree fndecl)
struct cgraph_node *cgn = cgraph_node (fndecl);
walk_tree (body_p, unmark_visited_r, NULL, NULL);
for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
unvisit_body (&DECL_SAVED_TREE (cgn->decl), cgn->decl);
if (body_p == &DECL_SAVED_TREE (fndecl))
for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
unvisit_body (&DECL_SAVED_TREE (cgn->decl), cgn->decl);
}
/* Unshare T and all the trees reached from T via TREE_CHAIN. */
@ -890,7 +877,7 @@ gimplify_bind_expr (tree *expr_p, tree temp, tree *pre_p)
/* Mark variables seen in this bind expr. */
for (t = BIND_EXPR_VARS (bind_expr); t ; t = TREE_CHAIN (t))
t->decl.seen_in_bind_expr = 1;
DECL_SEEN_IN_BIND_EXPR_P (t) = 1;
gimple_push_bind_expr (bind_expr);
gimplify_ctxp->save_stack = false;
@ -1668,7 +1655,8 @@ gimplify_compound_lval (tree *expr_p, tree *pre_p,
tret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval, fallback);
ret = MIN (ret, tret);
/* And finally, the indices and operands to BIT_FIELD_REF. */
/* And finally, the indices and operands to BIT_FIELD_REF. During this
loop we also remove any useless conversions. */
for (; VARRAY_ACTIVE_SIZE (stack) > 0; )
{
tree t = VARRAY_TOP_TREE (stack);
@ -1700,7 +1688,9 @@ gimplify_compound_lval (tree *expr_p, tree *pre_p,
is_gimple_val, fb_rvalue);
ret = MIN (ret, tret);
}
STRIP_USELESS_TYPE_CONVERSION (TREE_OPERAND (t, 0));
/* The innermost expression P may have originally had TREE_SIDE_EFFECTS
set which would have caused all the outer expressions in EXPR_P
leading to P to also have had TREE_SIDE_EFFECTS set. */
@ -2321,7 +2311,7 @@ gimplify_modify_expr_to_memcpy (tree *expr_p, bool want_value)
to = TREE_OPERAND (*expr_p, 0);
from = TREE_OPERAND (*expr_p, 1);
t = TYPE_SIZE_UNIT (TREE_TYPE (to));
t = TYPE_SIZE_UNIT (TREE_TYPE (from));
t = unshare_expr (t);
t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, to);
t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, from);
@ -2356,7 +2346,7 @@ gimplify_modify_expr_to_memset (tree *expr_p, bool want_value)
to = TREE_OPERAND (*expr_p, 0);
t = TYPE_SIZE_UNIT (TREE_TYPE (to));
t = TYPE_SIZE_UNIT (TREE_TYPE (TREE_OPERAND (*expr_p, 1)));
t = unshare_expr (t);
t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, to);
args = tree_cons (NULL, t, NULL);
@ -2772,8 +2762,15 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
/* If the value being copied is of variable width, expose the length
if the copy by converting the whole thing to a memcpy/memset.
Note that we need to do this before gimplifying any of the operands
so that we can resolve any PLACEHOLDER_EXPRs in the size. */
if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (*to_p))) != INTEGER_CST)
so that we can resolve any PLACEHOLDER_EXPRs in the size.
Also note that the RTL expander uses the size of the expression to
be copied, not of the destination, so that is what we must here.
The types on both sides of the MODIFY_EXPR should be the same,
but they aren't always and there are problems with class-wide types
in Ada where it's hard to make it "correct". */
if (TREE_CODE (TREE_TYPE (*from_p)) != ERROR_MARK
&& TYPE_SIZE_UNIT (TREE_TYPE (*from_p))
&& TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (*from_p))) != INTEGER_CST)
{
if (TREE_CODE (*from_p) == CONSTRUCTOR)
return gimplify_modify_expr_to_memset (expr_p, want_value);
@ -3361,7 +3358,7 @@ gimplify_target_expr (tree *expr_p, tree *pre_p, tree *post_p)
TREE_OPERAND (targ, 3) = init;
TARGET_EXPR_INITIAL (targ) = NULL_TREE;
}
else if (!temp->decl.seen_in_bind_expr)
else if (!DECL_SEEN_IN_BIND_EXPR_P (temp))
/* We should have expanded this before. */
abort ();
@ -3699,8 +3696,20 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
break;
case CONSTRUCTOR:
/* Don't reduce this in place; let gimplify_init_constructor work
its magic. */
/* Don't reduce this in place; let gimplify_init_constructor work its
magic. Buf if we're just elaborating this for side effects, just
gimplify any element that has side-effects. */
if (fallback == fb_none)
{
for (tmp = CONSTRUCTOR_ELTS (*expr_p); tmp;
tmp = TREE_CHAIN (tmp))
if (TREE_SIDE_EFFECTS (TREE_VALUE (tmp)))
gimplify_expr (&TREE_VALUE (tmp), pre_p, post_p,
gimple_test_f, fallback);
*expr_p = NULL_TREE;
}
ret = GS_ALL_DONE;
break;
@ -3801,7 +3810,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
tmp = *expr_p;
if (!TREE_STATIC (tmp) && !DECL_EXTERNAL (tmp)
&& decl_function_context (tmp) == current_function_decl
&& !tmp->decl.seen_in_bind_expr)
&& !DECL_SEEN_IN_BIND_EXPR_P (tmp))
{
#ifdef ENABLE_CHECKING
if (!errorcount && !sorrycount)

View File

@ -766,7 +766,7 @@ setup_one_parameter (inline_data *id, tree p, tree value, tree fn,
*vars = var;
/* Make gimplifier happy about this variable. */
var->decl.seen_in_bind_expr = lang_hooks.gimple_before_inlining;
DECL_SEEN_IN_BIND_EXPR_P (var) = lang_hooks.gimple_before_inlining;
/* Even if P was TREE_READONLY, the new VAR should not be.
In the original code, we would have constructed a
@ -1951,6 +1951,100 @@ save_body (tree fn, tree *arg_copy)
return body;
}
#define WALK_SUBTREE(NODE) \
do \
{ \
result = walk_tree (&(NODE), func, data, htab); \
if (result) \
return result; \
} \
while (0)
/* This is a subroutine of walk_tree that walks field of TYPE that are to
be walked whenever a type is seen in the tree. Rest of operands and return
value are as for walk_tree. */
static tree
walk_type_fields (tree type, walk_tree_fn func, void *data, void *htab)
{
tree result = NULL_TREE;
switch (TREE_CODE (type))
{
case POINTER_TYPE:
case REFERENCE_TYPE:
/* We have to worry about mutually recursive pointers. These can't
be written in C. They can in Ada. It's pathlogical, but
there's an ACATS test (c38102a) that checks it. Deal with this
by checking if we're pointing to another pointer, that one
points to another pointer, that one does too, and we have no htab.
If so, get a hash table. We check three levels deep to avoid
the cost of the hash table if we don't need one. */
if (POINTER_TYPE_P (TREE_TYPE (type))
&& POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (type)))
&& POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (TREE_TYPE (type))))
&& !htab)
{
result = walk_tree_without_duplicates (&TREE_TYPE (type),
func, data);
if (result)
return result;
break;
}
/* ... fall through ... */
case COMPLEX_TYPE:
WALK_SUBTREE (TREE_TYPE (type));
break;
case METHOD_TYPE:
WALK_SUBTREE (TYPE_METHOD_BASETYPE (type));
/* Fall through. */
case FUNCTION_TYPE:
WALK_SUBTREE (TREE_TYPE (type));
{
tree arg;
/* We never want to walk into default arguments. */
for (arg = TYPE_ARG_TYPES (type); arg; arg = TREE_CHAIN (arg))
WALK_SUBTREE (TREE_VALUE (arg));
}
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)
WALK_SUBTREE (TREE_TYPE (type));
WALK_SUBTREE (TYPE_DOMAIN (type));
break;
case BOOLEAN_TYPE:
case ENUMERAL_TYPE:
case INTEGER_TYPE:
case CHAR_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));
break;
default:
break;
}
return NULL_TREE;
}
/* Apply FUNC to all the sub-trees of TP in a pre-order traversal. FUNC is
called with the DATA and the address of each sub-tree. If FUNC returns a
non-NULL value, the traversal is aborted, and the value returned by FUNC
@ -1965,15 +2059,6 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
int walk_subtrees;
tree result;
#define WALK_SUBTREE(NODE) \
do \
{ \
result = walk_tree (&(NODE), func, data, htab); \
if (result) \
return result; \
} \
while (0)
#define WALK_SUBTREE_TAIL(NODE) \
do \
{ \
@ -2025,43 +2110,42 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
if (result || ! walk_subtrees)
return result;
/* If this is a DECL_EXPR, walk into various fields of the type or variable
that it's defining. We only want to walk into these fields of a decl
or type in this case.
/* If this is a 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 (code == DECL_EXPR
&& TREE_CODE (DECL_EXPR_DECL (*tp)) != ERROR_MARK
&& TREE_CODE (DECL_EXPR_DECL (*tp)) == TYPE_DECL
&& TREE_CODE (TREE_TYPE (DECL_EXPR_DECL (*tp))) != ERROR_MARK)
{
tree decl = DECL_EXPR_DECL (*tp);
tree type = TREE_TYPE (decl);
tree *type_p = &TREE_TYPE (DECL_EXPR_DECL (*tp));
/* Walk into fields of the DECL if it's not a type. */
if (TREE_CODE (decl) != TYPE_DECL)
{
if (TREE_CODE (decl) != FIELD_DECL && TREE_CODE (decl) != PARM_DECL)
WALK_SUBTREE (DECL_INITIAL (decl));
/* 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;
WALK_SUBTREE (DECL_SIZE (decl));
WALK_SUBTREE_TAIL (DECL_SIZE_UNIT (decl));
}
result = walk_type_fields (*type_p, func, data, htab_);
if (result)
return result;
/* Otherwise, we are declaring a type. First do the common fields via
recursion, then the fields we only do when we are declaring the type
or object. */
WALK_SUBTREE (type);
WALK_SUBTREE (TYPE_SIZE (type));
WALK_SUBTREE (TYPE_SIZE_UNIT (type));
WALK_SUBTREE (TYPE_SIZE (*type_p));
WALK_SUBTREE (TYPE_SIZE_UNIT (*type_p));
/* If this is a record type, also walk the fields. */
if (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE
|| TREE_CODE (type) == QUAL_UNION_TYPE)
if (TREE_CODE (*type_p) == RECORD_TYPE
|| TREE_CODE (*type_p) == UNION_TYPE
|| TREE_CODE (*type_p) == QUAL_UNION_TYPE)
{
tree field;
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
for (field = TYPE_FIELDS (*type_p); field;
field = TREE_CHAIN (field))
{
/* We'd like to look at the type of the field, but we can easily
get infinite recursion. So assume it's pointed to elsewhere
@ -2072,7 +2156,7 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
WALK_SUBTREE (DECL_FIELD_OFFSET (field));
WALK_SUBTREE (DECL_SIZE (field));
WALK_SUBTREE (DECL_SIZE_UNIT (field));
if (TREE_CODE (type) == QUAL_UNION_TYPE)
if (TREE_CODE (*type_p) == QUAL_UNION_TYPE)
WALK_SUBTREE (DECL_QUALIFIER (field));
}
}
@ -2114,6 +2198,13 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
#endif
}
/* If this is a type, walk the needed fields in the type. */
else if (TYPE_P (*tp))
{
result = walk_type_fields (*tp, func, data, htab_);
if (result)
return result;
}
else
{
/* Not one of the easy cases. We must explicitly go through the
@ -2126,8 +2217,6 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
case REAL_CST:
case VECTOR_CST:
case STRING_CST:
case VECTOR_TYPE:
case VOID_TYPE:
case BLOCK:
case PLACEHOLDER_EXPR:
case SSA_NAME:
@ -2183,7 +2272,6 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
WALK_SUBTREE (DECL_INITIAL (decl));
WALK_SUBTREE (DECL_SIZE (decl));
WALK_SUBTREE (DECL_SIZE_UNIT (decl));
WALK_SUBTREE (TREE_TYPE (decl));
}
WALK_SUBTREE_TAIL (BIND_EXPR_BODY (*tp));
}
@ -2196,70 +2284,6 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
}
break;
case POINTER_TYPE:
case REFERENCE_TYPE:
/* We have to worry about mutually recursive pointers. These can't
be written in C. They can in Ada. It's pathlogical, but
there's an ACATS test (c38102a) that checks it. Deal with this
by checking if we're pointing to another pointer, that one
points to another pointer, that one does too, and we have no htab.
If so, get a hash table. We check three levels deep to avoid
the cost of the hash table if we don't need one. */
if (POINTER_TYPE_P (TREE_TYPE (*tp))
&& POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (*tp)))
&& POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (TREE_TYPE (*tp))))
&& !htab)
{
result = walk_tree_without_duplicates (&TREE_TYPE (*tp),
func, data);
if (result)
return result;
break;
}
/* ... fall through ... */
case COMPLEX_TYPE:
WALK_SUBTREE_TAIL (TREE_TYPE (*tp));
break;
case METHOD_TYPE:
WALK_SUBTREE (TYPE_METHOD_BASETYPE (*tp));
/* Fall through. */
case FUNCTION_TYPE:
WALK_SUBTREE (TREE_TYPE (*tp));
{
tree arg;
/* We never want to walk into default arguments. */
for (arg = TYPE_ARG_TYPES (*tp); arg; arg = TREE_CHAIN (arg))
WALK_SUBTREE (TREE_VALUE (arg));
}
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 (*tp))
&& TREE_CODE (TREE_TYPE (*tp)) != OFFSET_TYPE)
WALK_SUBTREE (TREE_TYPE (*tp));
WALK_SUBTREE_TAIL (TYPE_DOMAIN (*tp));
case BOOLEAN_TYPE:
case ENUMERAL_TYPE:
case INTEGER_TYPE:
case CHAR_TYPE:
case REAL_TYPE:
WALK_SUBTREE (TYPE_MIN_VALUE (*tp));
WALK_SUBTREE_TAIL (TYPE_MAX_VALUE (*tp));
case OFFSET_TYPE:
WALK_SUBTREE (TREE_TYPE (*tp));
WALK_SUBTREE_TAIL (TYPE_OFFSET_BASETYPE (*tp));
default:
/* ??? This could be a language-defined node. We really should make
a hook for it, but right now just ignore it. */
@ -2498,7 +2522,7 @@ declare_inline_vars (tree bind_expr, tree vars)
tree t;
for (t = vars; t; t = TREE_CHAIN (t))
vars->decl.seen_in_bind_expr = 1;
DECL_SEEN_IN_BIND_EXPR_P (t) = 1;
}
add_var_to_bind_expr (bind_expr, vars);

View File

@ -145,6 +145,7 @@ create_tmp_var_for (struct nesting_info *info, tree type, const char *prefix)
tmp_var = create_tmp_var_raw (type, prefix);
DECL_CONTEXT (tmp_var) = info->context;
TREE_CHAIN (tmp_var) = info->new_local_var_chain;
DECL_SEEN_IN_BIND_EXPR_P (tmp_var) = 1;
info->new_local_var_chain = tmp_var;
return tmp_var;

View File

@ -1985,6 +1985,11 @@ extern GTY (()) unsigned binfo_lang_slots;
#define DECL_DECLARED_INLINE_P(NODE) \
(FUNCTION_DECL_CHECK (NODE)->decl.declared_inline_flag)
/* Nonzero in a decl means that the gimplifier has seen (or placed)
this variable in a BIND_EXPR. */
#define DECL_SEEN_IN_BIND_EXPR_P(NODE) \
(DECL_CHECK (NODE)->decl.seen_in_bind_expr)
/* In a VAR_DECL, nonzero if the decl is a register variable with
an explicit asm specification. */
#define DECL_HARD_REGISTER(NODE) (DECL_CHECK (NODE)->decl.inline_flag)