* 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
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.
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)
{
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))
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)
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. */
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. */
/* 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;
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);
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. */
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);
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);
/* 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);
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 ();
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;
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)
*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
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
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 \
{ \
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
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));
}
}
#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
case REAL_CST:
case VECTOR_CST:
case STRING_CST:
- case VECTOR_TYPE:
- case VOID_TYPE:
case BLOCK:
case PLACEHOLDER_EXPR:
case SSA_NAME:
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));
}
}
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. */
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);
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;
#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)