This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[tree-ssa] Lowering of VLA's, part 2
Hello,
this patch makes deallocation of stack explicit, thus making vla's as
independent on bind_exprs as any other variable (at least for C
frontend; do other frontends produce them too? If so, they should
be converted -- it is enough to set them DECL_DEFER_OUTPUT and emit
call to stack_alloc for them, the rest is done automatically).
Zdenek
* builtins.c (expand_builtin): Expand BUILT_IN_STACK_SAVE and
BUILT_IN_STACK_RESTORE.
* builtins.def (BUILT_IN_STACK_SAVE, BUILT_IN_STACK_RESTORE): New.
* gimplify.c (struct tree_p_list): New type.
(join_tree_p_list, add_tree_p_list, free_tree_p_list,
build_stack_save_restore, prepend_to_exit_gotos): New functions.
(struct gimplify_ctx): New fields current_bind_expr_gotos,
current_bind_expr_labels and save_stack.
(push_gimplify_context, pop_gimplify_context): Initialize them.
(gimple_push_bind_expr, gimple_pop_bind_expr): Update them.
(gimplify_bind_expr, gimplify_expr, gimplify_call_expr): Arrange save
of stack on BIND_EXPR entry and restore on exits.
* stmt.c (expand_stack_alloc): Saving of stack removed.
(expand_stack_save, expand_stack_restore): New.
* tree.h (expand_stack_save, expand_stack_restore): Declare.
Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.152.2.31
diff -c -3 -p -r1.152.2.31 builtins.c
*** builtins.c 26 Aug 2003 22:29:33 -0000 1.152.2.31
--- builtins.c 27 Aug 2003 17:31:55 -0000
*************** expand_builtin (tree exp, rtx target, rt
*** 5026,5032 ****
case BUILT_IN_STACK_ALLOC:
expand_stack_alloc (TREE_VALUE (arglist),
TREE_VALUE (TREE_CHAIN (arglist)));
! return NULL_RTX;
case BUILT_IN_FFS:
case BUILT_IN_FFSL:
--- 5026,5039 ----
case BUILT_IN_STACK_ALLOC:
expand_stack_alloc (TREE_VALUE (arglist),
TREE_VALUE (TREE_CHAIN (arglist)));
! return const0_rtx;
!
! case BUILT_IN_STACK_SAVE:
! return expand_stack_save ();
!
! case BUILT_IN_STACK_RESTORE:
! expand_stack_restore (TREE_VALUE (arglist));
! return const0_rtx;
case BUILT_IN_FFS:
case BUILT_IN_FFSL:
Index: builtins.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.def,v
retrieving revision 1.29.2.21
diff -c -3 -p -r1.29.2.21 builtins.def
*** builtins.def 26 Aug 2003 22:29:33 -0000 1.29.2.21
--- builtins.def 27 Aug 2003 17:31:55 -0000
*************** DEF_GCC_BUILTIN (BUILT_IN_RETURN_
*** 318,323 ****
--- 318,325 ----
DEF_GCC_BUILTIN (BUILT_IN_SAVEREGS, "saveregs", BT_FN_PTR_VAR, ATTR_NULL)
DEF_GCC_BUILTIN (BUILT_IN_SETJMP, "setjmp", BT_FN_INT_PTR, ATTR_NULL)
DEF_GCC_BUILTIN (BUILT_IN_STACK_ALLOC, "stack_alloc", BT_FN_VOID_PTR_SIZE, ATTR_NULL)
+ DEF_GCC_BUILTIN (BUILT_IN_STACK_SAVE, "stack_save", BT_FN_PTR, ATTR_NULL)
+ DEF_GCC_BUILTIN (BUILT_IN_STACK_RESTORE, "stack_restore", BT_FN_VOID_PTR, ATTR_NULL)
DEF_GCC_BUILTIN (BUILT_IN_STDARG_START, "stdarg_start", BT_FN_VOID_VALIST_REF_VAR, ATTR_NULL)
DEF_EXT_LIB_BUILTIN (BUILT_IN_STRFMON, "strfmon", BT_FN_SSIZE_STRING_SIZE_CONST_STRING_VAR, ATTR_FORMAT_STRFMON_3_4)
DEF_LIB_BUILTIN (BUILT_IN_STRFTIME, "strftime", BT_FN_SIZE_STRING_SIZE_CONST_STRING_CONST_PTR, ATTR_FORMAT_STRFTIME_3_0)
Index: gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/gimplify.c,v
retrieving revision 1.1.2.74
diff -c -3 -p -r1.1.2.74 gimplify.c
*** gimplify.c 26 Aug 2003 22:21:16 -0000 1.1.2.74
--- gimplify.c 27 Aug 2003 17:32:51 -0000
*************** Software Foundation, 59 Temple Place - S
*** 42,47 ****
--- 42,53 ----
#include "flags.h"
#include "real.h"
+ struct tree_p_list
+ {
+ tree *elt;
+ struct tree_p_list *next;
+ };
+
static void gimplify_constructor (tree, tree *, tree *);
static void gimplify_array_ref (tree *, tree *, tree *, int);
static void gimplify_array_ref_to_plus (tree *, tree *, tree *);
*************** static tree build_addr_expr (tree);
*** 59,65 ****
static tree build_addr_expr_with_type (tree, tree);
static tree add_stmt_to_compound (tree, tree);
static void gimplify_asm_expr (tree, tree *);
! static void gimplify_bind_expr (tree *, tree *);
static inline void remove_suffix (char *, int);
static void push_gimplify_context (void);
static void pop_gimplify_context (void);
--- 65,71 ----
static tree build_addr_expr_with_type (tree, tree);
static tree add_stmt_to_compound (tree, tree);
static void gimplify_asm_expr (tree, tree *);
! static void gimplify_bind_expr (tree *, tree *, tree *);
static inline void remove_suffix (char *, int);
static void push_gimplify_context (void);
static void pop_gimplify_context (void);
*************** static tree gimple_boolify (tree);
*** 89,98 ****
--- 95,113 ----
static void gimplify_conversion (tree *);
static int gimplify_init_constructor (tree *, tree *, int);
static void gimplify_minimax_expr (tree *, tree *, tree *);
+ static void join_tree_p_list (struct tree_p_list **);
+ static void add_tree_p_list (struct tree_p_list **, tree *);
+ static void free_tree_p_list (struct tree_p_list **);
+ static void build_stack_save_restore (tree *, tree *);
+ static void prepend_to_exit_gotos (struct tree_p_list **, struct tree_p_list *,
+ tree);
static struct gimplify_ctx
{
tree current_bind_expr;
+ struct tree_p_list *current_bind_expr_gotos;
+ struct tree_p_list *current_bind_expr_labels;
+ bool save_stack;
tree temps;
tree conditional_cleanups;
int conditions;
*************** static struct gimplify_ctx
*** 102,107 ****
--- 117,160 ----
htab_t temp_htab;
} *gimplify_ctxp;
+ /* Joins two segments of LIST. */
+ static void
+ join_tree_p_list (struct tree_p_list **list)
+ {
+ struct tree_p_list *act;
+
+ while ((*list)->elt)
+ list = &(*list)->next;
+
+ act = *list;
+ *list = (*list)->next;
+ free (act);
+ }
+
+ /* Adds ELT to the LIST. */
+ static void
+ add_tree_p_list (struct tree_p_list **list, tree *elt)
+ {
+ struct tree_p_list *nw = xmalloc (sizeof (struct tree_p_list));
+
+ nw->elt = elt;
+ nw->next = *list;
+ *list = nw;
+ }
+
+ /* Releases the LIST. */
+ static void
+ free_tree_p_list (struct tree_p_list **list)
+ {
+ struct tree_p_list *next;
+
+ for (; *list; *list = next)
+ {
+ next = (*list)->next;
+ free (*list);
+ }
+ }
+
static void
push_gimplify_context (void)
{
*************** push_gimplify_context (void)
*** 116,121 ****
--- 169,176 ----
static void
pop_gimplify_context (void)
{
+ struct tree_p_list *l;
+
if (!gimplify_ctxp || gimplify_ctxp->current_bind_expr)
abort ();
#if 0
*************** pop_gimplify_context (void)
*** 124,129 ****
--- 179,192 ----
htab_collisions (gimplify_ctxp->temp_htab));
#endif
htab_delete (gimplify_ctxp->temp_htab);
+
+ free_tree_p_list (&gimplify_ctxp->current_bind_expr_gotos);
+ /* Reset DECL_TOO_LATE for the labels, so that it is ready for use in
+ tree->rtl expansion. */
+ for (l = gimplify_ctxp->current_bind_expr_labels; l; l = l->next)
+ if (l->elt)
+ DECL_TOO_LATE (*l->elt) = 0;
+ free_tree_p_list (&gimplify_ctxp->current_bind_expr_labels);
free (gimplify_ctxp);
gimplify_ctxp = NULL;
}
*************** gimple_push_bind_expr (tree bind)
*** 133,138 ****
--- 196,205 ----
{
TREE_CHAIN (bind) = gimplify_ctxp->current_bind_expr;
gimplify_ctxp->current_bind_expr = bind;
+
+ /* Separate the records of gotos and labels in the bind exprs. */
+ add_tree_p_list (&gimplify_ctxp->current_bind_expr_gotos, NULL);
+ add_tree_p_list (&gimplify_ctxp->current_bind_expr_labels, NULL);
}
void
*************** gimple_pop_bind_expr (void)
*** 140,145 ****
--- 207,216 ----
{
gimplify_ctxp->current_bind_expr
= TREE_CHAIN (gimplify_ctxp->current_bind_expr);
+
+ /* Add the list of gotos and labels to the outer list. */
+ join_tree_p_list (&gimplify_ctxp->current_bind_expr_gotos);
+ join_tree_p_list (&gimplify_ctxp->current_bind_expr_labels);
}
tree
*************** gimplify_expr (tree *expr_p, tree *pre_p
*** 512,518 ****
break;
case BIND_EXPR:
! gimplify_bind_expr (expr_p, pre_p);
break;
case LOOP_EXPR:
--- 583,589 ----
break;
case BIND_EXPR:
! gimplify_bind_expr (expr_p, pre_p, post_p);
break;
case LOOP_EXPR:
*************** gimplify_expr (tree *expr_p, tree *pre_p
*** 556,565 ****
--- 627,649 ----
FUNCTION_RECEIVES_NONLOCAL_GOTO (context) = 1;
}
+ if (TREE_CODE (dest) == LABEL_DECL)
+ {
+ add_tree_p_list (&gimplify_ctxp->current_bind_expr_gotos,
+ expr_p);
+
+ /* If we jump to a label with DECL_TOO_LATE, this is an
+ error. */
+ if (DECL_TOO_LATE (dest))
+ error ("jump to `%s' invalidly jumps into binding contour",
+ IDENTIFIER_POINTER (DECL_NAME (dest)));
+ }
break;
}
case LABEL_EXPR:
+ add_tree_p_list (&gimplify_ctxp->current_bind_expr_labels,
+ &LABEL_EXPR_LABEL (*expr_p));
break;
case CASE_LABEL_EXPR:
*************** voidify_wrapper_expr (tree wrapper)
*** 875,887 ****
/* Gimplify a BIND_EXPR. Just voidify and recurse. */
static void
! gimplify_bind_expr (tree *expr_p, tree *pre_p)
{
tree bind_expr = *expr_p;
tree temp = voidify_wrapper_expr (bind_expr);
gimple_push_bind_expr (bind_expr);
gimplify_stmt (&BIND_EXPR_BODY (bind_expr));
gimple_pop_bind_expr ();
if (temp)
--- 959,990 ----
/* Gimplify a BIND_EXPR. Just voidify and recurse. */
static void
! gimplify_bind_expr (tree *expr_p, tree *pre_p, tree *post_p)
{
tree bind_expr = *expr_p;
tree temp = voidify_wrapper_expr (bind_expr);
+ bool old_save_stack = gimplify_ctxp->save_stack;
gimple_push_bind_expr (bind_expr);
+ gimplify_ctxp->save_stack = false;
+
gimplify_stmt (&BIND_EXPR_BODY (bind_expr));
+ if (gimplify_ctxp->save_stack)
+ {
+ tree stack_save, stack_restore;
+
+ /* Save stack on entry and restore it on exit. Also add restores
+ to exits through gotos. */
+ build_stack_save_restore (&stack_save, &stack_restore);
+ add_tree (stack_save, pre_p);
+ add_tree (stack_restore, post_p);
+
+ prepend_to_exit_gotos (&gimplify_ctxp->current_bind_expr_gotos,
+ gimplify_ctxp->current_bind_expr_labels,
+ stack_restore);
+ }
+
+ gimplify_ctxp->save_stack = old_save_stack;
gimple_pop_bind_expr ();
if (temp)
*************** gimplify_call_expr (tree *expr_p, tree *
*** 1584,1589 ****
--- 1687,1697 ----
return;
}
+ /* If it is allocation of stack, record the need to restore the memory
+ when the enclosing bind_expr is exited. */
+ if (DECL_FUNCTION_CODE (decl) == BUILT_IN_STACK_ALLOC)
+ gimplify_ctxp->save_stack = true;
+
new = simplify_builtin (*expr_p, gimple_test_f == is_gimple_stmt);
if (new && new != *expr_p)
*************** gimplify_target_expr (tree *expr_p, tree
*** 2930,2933 ****
--- 3038,3136 ----
}
*expr_p = temp;
+ }
+
+ /* Prepare calls to builtins to SAVE and RESTORE the stack as well as temporary
+ through that they comunicate. */
+ static void
+ build_stack_save_restore (tree *save, tree *restore)
+ {
+ tree save_call, tmp_var;
+
+ save_call = build_function_call_expr (
+ implicit_built_in_decls[BUILT_IN_STACK_SAVE],
+ NULL_TREE);
+ tmp_var = create_tmp_var (ptr_type_node, "saved_stack");
+
+ *save = build (MODIFY_EXPR, ptr_type_node, tmp_var, save_call);
+ *restore = build_function_call_expr (
+ implicit_built_in_decls[BUILT_IN_STACK_RESTORE],
+ tree_cons (NULL_TREE, tmp_var, NULL_TREE));
+ }
+
+ /* Prepends copy of statement STMT to gotos from list GOTOS that lead
+ to labels not in list LABELS. */
+ static void
+ prepend_to_exit_gotos (struct tree_p_list **gotos, struct tree_p_list *labels,
+ tree stmt)
+ {
+ htab_t labels_t;
+ struct tree_p_list *act;
+
+ labels_t = htab_create (10, htab_hash_pointer, htab_eq_pointer, NULL);
+
+ /* Prepare a hash table of labels. */
+ for (; labels->elt; labels = labels->next)
+ {
+ void **slot = htab_find_slot (labels_t, *labels->elt, INSERT);
+
+ /* Mark the label so that we may issue errors for gotos into this
+ bind_expr. */
+ DECL_TOO_LATE (*labels->elt) = 1;
+
+ if (!*slot)
+ *slot = *labels->elt;
+ }
+
+ for (; (*gotos)->elt; )
+ {
+ tree insert;
+ tree *elt = (*gotos)->elt;
+ void *lab = htab_find (labels_t, GOTO_DESTINATION (*elt));
+
+ if (lab)
+ {
+ /* The goto is local from this bind_expr up, so remove it so that
+ it is not processed unnecesarily later. */
+ act = *gotos;
+ *gotos = (*gotos)->next;
+ free (act);
+ continue;
+ }
+
+ insert = unshare_expr (stmt);
+
+ /* Since we don't know the goto_expr's container, prepending the
+ statement involves creating a bind_expr wrapper. */
+ *elt = build (BIND_EXPR, void_type_node, NULL_TREE,
+ build (COMPOUND_EXPR, void_type_node,
+ insert,
+ *elt),
+ NULL_TREE);
+ recalculate_side_effects (*elt);
+
+ /* Make the gotos->elt point to goto statement again so that outer
+ bind_exprs that it might exit are happy. */
+ (*gotos)->elt = &TREE_OPERAND (BIND_EXPR_BODY (*elt), 1);
+ gotos = &(*gotos)->next;
+ }
+
+ /* Go through all the remaining goto_exprs in the list and check whether
+ they jump to one of lables inside this bind_expr. If they do, it is
+ an error. */
+ for (; *gotos; gotos = &(*gotos)->next)
+ {
+ tree *elt = (*gotos)->elt;
+ void *lab;
+
+ if (!elt)
+ continue;
+ lab = htab_find (labels_t, GOTO_DESTINATION (*elt));
+
+ if (lab)
+ error ("jump to `%s' invalidly jumps into binding contour",
+ IDENTIFIER_POINTER (DECL_NAME (GOTO_DESTINATION (*elt))));
+ }
+
+ htab_delete (labels_t);
}
Index: stmt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/stmt.c,v
retrieving revision 1.267.2.28
diff -c -3 -p -r1.267.2.28 stmt.c
*** stmt.c 26 Aug 2003 22:29:34 -0000 1.267.2.28
--- stmt.c 27 Aug 2003 17:33:35 -0000
*************** expand_stack_alloc (tree alloc, tree t_s
*** 4059,4069 ****
type = TREE_TYPE (var);
- /* Record the stack pointer on entry to block, if have
- not already done so. */
- do_pending_stack_adjust ();
- save_stack_pointer ();
-
/* In function-at-a-time mode, variable_size doesn't expand this,
so do it now. */
if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
--- 4025,4030 ----
*************** expand_stack_alloc (tree alloc, tree t_s
*** 4087,4092 ****
--- 4048,4073 ----
DECL_ALIGN (var) = BIGGEST_ALIGNMENT;
#endif
DECL_USER_ALIGN (var) = 0;
+ }
+
+ /* Emit code to save the current value of stack. */
+ rtx
+ expand_stack_save ()
+ {
+ rtx ret = NULL_RTX;
+
+ do_pending_stack_adjust ();
+ emit_stack_save (SAVE_BLOCK, &ret, NULL_RTX);
+ return ret;
+ }
+
+ /* Emit code to restore the current value of stack. */
+ void
+ expand_stack_restore (tree var)
+ {
+ rtx sa = DECL_RTL (var);
+
+ emit_stack_restore (SAVE_BLOCK, sa, NULL_RTX);
}
/* Emit code to perform the initialization of a declaration DECL. */
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.342.2.91
diff -c -3 -p -r1.342.2.91 tree.h
*** tree.h 27 Aug 2003 04:31:36 -0000 1.342.2.91
--- tree.h 27 Aug 2003 17:42:05 -0000
*************** extern int expand_exit_loop_top_cond (st
*** 3093,3098 ****
--- 3093,3100 ----
extern int expand_exit_something (void);
extern void expand_stack_alloc (tree, tree);
+ extern rtx expand_stack_save (void);
+ extern void expand_stack_restore (tree);
extern void expand_return (tree);
extern int optimize_tail_recursion (tree, rtx);
extern void expand_start_bindings_and_block (int, tree);