Patchwork [6/6] Add manual GTY hooks

login
register
mail settings
Submitter David Malcolm
Date Aug. 29, 2013, 4:20 p.m.
Message ID <1377793216-22549-7-git-send-email-dmalcolm@redhat.com>
Download mbox | patch
Permalink /patch/270881/
State New
Headers show

Comments

David Malcolm - Aug. 29, 2013, 4:20 p.m.
* gimple.c (gt_ggc_mx (gimple)): New, as required by GTY((user)).
	(gt_pch_nx (gimple)): Likewise.
	(gt_pch_nx (gimple, gt_pointer_operator, void *)): Likewise.
	* gimple.h  (gt_ggc_mx (gimple)): Declare.
	(gt_pch_nx (gimple)): Declare.
	(gt_pch_nx (gimple, gt_pointer_operator, void *)): Declare.
	* tree-cfg.c (ggc_mx (gimple&)): Remove declaration, as this
	collides with the function that GTY((user)) expects.
	(gt_ggc_mx (edge_def *)): Replace call to gt_ggc_mx on the
	gimple with gt_ggc_mx_gimple_statement_base: in the
	pre-GTY((user)) world, "gt_ggc_mx" was the function to be called
	on a possibly NULL pointed to check if needed marking and if so
	to traverse its fields.  In the GTY((user)) world, "gt_ggc_mx"
	is the function to be called on non-NULL objects immediately *after*
	they have been marked: it does not mark the object itself.
	(gt_pch_nx (gimple&)): Remove declaration.
	(gt_pch_nx (edge_def *)): Update as per the mx hook.
---
 gcc/gimple.c   | 743 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/gimple.h   |   6 +
 gcc/tree-cfg.c |   6 +-
 3 files changed, 751 insertions(+), 4 deletions(-)
Steven Bosscher - Aug. 29, 2013, 7:44 p.m.
On Thu, Aug 29, 2013 at 6:20 PM, David Malcolm <dmalcolm@redhat.com> wrote:
>         * gimple.c (gt_ggc_mx (gimple)): New, as required by GTY((user)).
>         (gt_pch_nx (gimple)): Likewise.

GIMPLE isn't supposed to end up in a PCH. Can you please make this
function simply call gcc_unreachable()?

FWIW 1: I really think all these hand-written markers aren't a good
idea, we should really figure out a way to have automatic marker
function generators, something less complex than gengtype, of course.
But to have all these calls to the type-mangled marker functions
(gt_pch_n_9tree_node, etc.) is going to be a problem in the long term.

It seems to me that the first step in all these conversions to
hand-written markers should be to make gengtype spit out the marker
functions *without* the type name mangling, i.e. all marker functions
should just be gt_ggc_mx(type) / gt_pch_nx(type).

Ciao!
Steven
Richard Guenther - Aug. 30, 2013, 8:04 a.m.
On Thu, Aug 29, 2013 at 6:20 PM, David Malcolm <dmalcolm@redhat.com> wrote:
>         * gimple.c (gt_ggc_mx (gimple)): New, as required by GTY((user)).
>         (gt_pch_nx (gimple)): Likewise.
>         (gt_pch_nx (gimple, gt_pointer_operator, void *)): Likewise.
>         * gimple.h  (gt_ggc_mx (gimple)): Declare.
>         (gt_pch_nx (gimple)): Declare.
>         (gt_pch_nx (gimple, gt_pointer_operator, void *)): Declare.

No GIMPLE should reside in PCHs so you should be able to just put
gcc_unreachable () in them ... (if dropping them does not work)

>         * tree-cfg.c (ggc_mx (gimple&)): Remove declaration, as this
>         collides with the function that GTY((user)) expects.
>         (gt_ggc_mx (edge_def *)): Replace call to gt_ggc_mx on the
>         gimple with gt_ggc_mx_gimple_statement_base: in the
>         pre-GTY((user)) world, "gt_ggc_mx" was the function to be called
>         on a possibly NULL pointed to check if needed marking and if so
>         to traverse its fields.  In the GTY((user)) world, "gt_ggc_mx"
>         is the function to be called on non-NULL objects immediately *after*
>         they have been marked: it does not mark the object itself.
>         (gt_pch_nx (gimple&)): Remove declaration.
>         (gt_pch_nx (edge_def *)): Update as per the mx hook.
> ---
>  gcc/gimple.c   | 743 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  gcc/gimple.h   |   6 +
>  gcc/tree-cfg.c |   6 +-
>  3 files changed, 751 insertions(+), 4 deletions(-)
>
> diff --git a/gcc/gimple.c b/gcc/gimple.c
> index 1ad36d1..dd99cda 100644
> --- a/gcc/gimple.c
> +++ b/gcc/gimple.c
> @@ -4338,4 +4338,747 @@ build_type_cast (tree to_type, gimple op, enum ssa_mode mode)
>    return build_type_cast (to_type, gimple_assign_lhs (op), mode);
>  }
>
> +void
> +gt_ggc_mx (gimple gs)
> +{
> +  gimple x = gs;
> +  /* Emulation of the "chain_next" GTY attribute.
> +
> +     gs has already been marked.
> +     Iterate the chain of next statements, marking until we reach one that
> +     has already been marked, or NULL.   */
> +  gimple xlimit = gs->next;
> +  while (ggc_test_and_set_mark (xlimit))
> +    xlimit = xlimit->next;
> +
> +  /* All of the statements within the half-open interval [x..xlimit) have
> +     just been marked.  Iterate through the list, visiting their fields.  */
> +  while (x != xlimit)
> +    {
> +      gt_ggc_m_15basic_block_def (x->bb);
> +      switch (gimple_statement_structure (&((*x))))
> +       {
> +       case GSS_BASE:
> +         break;
> +       case GSS_WITH_OPS:
> +         {
> +           gimple_statement_with_ops *stmt
> +             = static_cast <gimple_statement_with_ops *> (x);
> +           size_t num = (size_t)(stmt->num_ops);
> +           for (size_t i = 0; i != num; i++)
> +             gt_ggc_m_9tree_node (stmt->op[i]);
> +         }
> +         break;
> +       case GSS_WITH_MEM_OPS_BASE:
> +         break;
> +       case GSS_WITH_MEM_OPS:
> +         {
> +           gimple_statement_with_memory_ops *stmt
> +             = static_cast <gimple_statement_with_memory_ops *> (x);
> +           size_t num = (size_t)(stmt->num_ops);
> +           for (size_t i = 0; i != num; i++)
> +             gt_ggc_m_9tree_node (stmt->op[i]);
> +         }
> +         break;
> +       case GSS_CALL:
> +         {
> +           gimple_statement_call *stmt
> +             = static_cast <gimple_statement_call *> (x);
> +           gt_ggc_m_15bitmap_head_def (stmt->call_used.vars);
> +           gt_ggc_m_15bitmap_head_def (stmt->call_clobbered.vars);
> +           switch (stmt->subcode & GF_CALL_INTERNAL)
> +             {
> +             case 0:
> +               gt_ggc_m_9tree_node (stmt->u.fntype);
> +               break;
> +             case GF_CALL_INTERNAL:
> +               break;
> +             default:
> +               break;
> +             }
> +           size_t num = (size_t)(stmt->num_ops);
> +           for (size_t i = 0; i != num; i++)
> +             gt_ggc_m_9tree_node (stmt->op[i]);
> +         }
> +         break;
> +       case GSS_OMP:
> +         {
> +           gimple_statement_omp *stmt
> +             = static_cast <gimple_statement_omp *> (x);
> +           gt_ggc_mx_gimple_statement_base (stmt->body);
> +         }
> +         break;
> +       case GSS_BIND:
> +         {
> +            gimple_statement_bind *stmt
> +             = static_cast <gimple_statement_bind *> (x);
> +           gt_ggc_m_9tree_node (stmt->vars);
> +           gt_ggc_m_9tree_node (stmt->block);
> +           gt_ggc_mx_gimple_statement_base (stmt->body);
> +         }
> +         break;
> +       case GSS_CATCH:
> +         {
> +           gimple_statement_catch *stmt
> +             = static_cast <gimple_statement_catch *> (x);
> +           gt_ggc_m_9tree_node (stmt->types);
> +           gt_ggc_mx_gimple_statement_base (stmt->handler);
> +         }
> +         break;
> +       case GSS_EH_FILTER:
> +         {
> +           gimple_statement_eh_filter *stmt
> +             = static_cast <gimple_statement_eh_filter *> (x);
> +           gt_ggc_m_9tree_node (stmt->types);
> +           gt_ggc_mx_gimple_statement_base (stmt->failure);
> +         }
> +         break;
> +       case GSS_EH_MNT:
> +         {
> +           gimple_statement_eh_mnt *stmt
> +             = static_cast <gimple_statement_eh_mnt *> (x);
> +           gt_ggc_m_9tree_node (stmt->fndecl);
> +         }
> +         break;
> +       case GSS_EH_ELSE:
> +         {
> +           gimple_statement_eh_else*stmt
> +             = static_cast <gimple_statement_eh_else *> (x);
> +           gt_ggc_mx_gimple_statement_base (stmt->n_body);
> +           gt_ggc_mx_gimple_statement_base (stmt->e_body);
> +         }
> +         break;
> +       case GSS_PHI:
> +         {
> +           gimple_statement_phi *stmt
> +             = static_cast <gimple_statement_phi *> (x);
> +           size_t num = (size_t)(stmt->nargs);
> +           gt_ggc_m_9tree_node (stmt->result);
> +           for (size_t i = 0; i != num; i++)
> +             gt_ggc_m_9tree_node (stmt->args[i].def);
> +         }
> +         break;
> +       case GSS_EH_CTRL:
> +         break;
> +       case GSS_TRY:
> +         {
> +           gimple_statement_try *stmt
> +             = static_cast <gimple_statement_try *> (x);
> +           gt_ggc_mx_gimple_statement_base (stmt->eval);
> +           gt_ggc_mx_gimple_statement_base (stmt->cleanup);
> +         }
> +         break;
> +       case GSS_WCE:
> +         {
> +           gimple_statement_wce *stmt
> +             = static_cast <gimple_statement_wce *> (x);
> +           gt_ggc_mx_gimple_statement_base (stmt->cleanup);
> +         }
> +         break;
> +       case GSS_ASM:
> +         {
> +           gimple_statement_asm *stmt
> +             = static_cast <gimple_statement_asm *> (x);
> +           size_t num = (size_t)(stmt->num_ops);
> +           gt_ggc_m_S (stmt->string);
> +           for (size_t i = 0; i != num; i++)
> +             gt_ggc_m_9tree_node (stmt->op[i]);
> +         }
> +         break;
> +       case GSS_OMP_CRITICAL:
> +         {
> +           gimple_statement_omp_critical *stmt
> +             = static_cast <gimple_statement_omp_critical *> (x);
> +           gt_ggc_mx_gimple_statement_base (stmt->body);
> +           gt_ggc_m_9tree_node (stmt->name);
> +         }
> +         break;
> +       case GSS_OMP_FOR:
> +         {
> +           gimple_statement_omp_for *stmt
> +             = static_cast <gimple_statement_omp_for *> (x);
> +           size_t num = (size_t)(stmt->collapse);
> +           gt_ggc_mx_gimple_statement_base (stmt->body);
> +           gt_ggc_m_9tree_node (stmt->clauses);
> +           if (stmt->iter != NULL) {
> +             for (size_t i = 0; i != num; i++) {
> +               gt_ggc_m_9tree_node (stmt->iter[i].index);
> +               gt_ggc_m_9tree_node (stmt->iter[i].initial);
> +               gt_ggc_m_9tree_node (stmt->iter[i].final);
> +               gt_ggc_m_9tree_node (stmt->iter[i].incr);
> +             }
> +             ggc_mark (stmt->iter);
> +           }
> +           gt_ggc_mx_gimple_statement_base (stmt->pre_body);
> +         }
> +         break;
> +       case GSS_OMP_PARALLEL:
> +         {
> +           gimple_statement_omp_parallel *stmt
> +             = static_cast <gimple_statement_omp_parallel *> (x);
> +           gt_ggc_mx_gimple_statement_base (stmt->body);
> +           gt_ggc_m_9tree_node (stmt->clauses);
> +           gt_ggc_m_9tree_node (stmt->child_fn);
> +           gt_ggc_m_9tree_node (stmt->data_arg);
> +         }
> +         break;
> +       case GSS_OMP_TASK:
> +         {
> +           gimple_statement_omp_task *stmt
> +             = static_cast <gimple_statement_omp_task *> (x);
> +           gt_ggc_mx_gimple_statement_base (stmt->body);
> +           gt_ggc_m_9tree_node (stmt->clauses);
> +           gt_ggc_m_9tree_node (stmt->child_fn);
> +           gt_ggc_m_9tree_node (stmt->data_arg);
> +           gt_ggc_m_9tree_node (stmt->copy_fn);
> +           gt_ggc_m_9tree_node (stmt->arg_size);
> +           gt_ggc_m_9tree_node (stmt->arg_align);
> +         }
> +         break;
> +       case GSS_OMP_SECTIONS:
> +         {
> +           gimple_statement_omp_sections *stmt
> +             = static_cast <gimple_statement_omp_sections *> (x);
> +           gt_ggc_mx_gimple_statement_base (stmt->body);
> +           gt_ggc_m_9tree_node (stmt->clauses);
> +           gt_ggc_m_9tree_node (stmt->control);
> +         }
> +         break;
> +       case GSS_OMP_SINGLE:
> +         {
> +           gimple_statement_omp_single *stmt
> +             = static_cast <gimple_statement_omp_single *> (x);
> +           gt_ggc_mx_gimple_statement_base (stmt->body);
> +           gt_ggc_m_9tree_node (stmt->clauses);
> +         }
> +         break;
> +       case GSS_OMP_CONTINUE:
> +         {
> +           gimple_statement_omp_continue *stmt
> +             = static_cast <gimple_statement_omp_continue *> (x);
> +           gt_ggc_m_9tree_node (stmt->control_def);
> +           gt_ggc_m_9tree_node (stmt->control_use);
> +         }
> +         break;
> +       case GSS_OMP_ATOMIC_LOAD:
> +         {
> +           gimple_statement_omp_atomic_load *stmt
> +             = static_cast <gimple_statement_omp_atomic_load *> (x);
> +           gt_ggc_m_9tree_node (stmt->rhs);
> +           gt_ggc_m_9tree_node (stmt->lhs);
> +         }
> +         break;
> +       case GSS_OMP_ATOMIC_STORE:
> +         {
> +           gimple_statement_omp_atomic_store *stmt
> +             = static_cast <gimple_statement_omp_atomic_store *> (x);
> +           gt_ggc_m_9tree_node (stmt->val);
> +         }
> +         break;
> +       case GSS_TRANSACTION:
> +         {
> +           gimple_statement_transaction *stmt
> +             = static_cast <gimple_statement_transaction *> (x);
> +           gt_ggc_mx_gimple_statement_base (stmt->body);
> +           gt_ggc_m_9tree_node (stmt->label);
> +         }
> +         break;
> +       default:
> +         break;
> +       }
> +      x = x->next;
> +    }
> +}
> +
> +void
> +gt_pch_nx (gimple gs)
> +{
> +  gimple x = gs;
> +  /* Emulation of the "chain_next" GTY attribute.
> +
> +     gs has already been marked.
> +     Iterate the chain of next statements, marking until we reach one that
> +     has already been marked, or NULL.   */
> +  gimple xlimit = gs->next;
> +  while (gt_pch_note_object (xlimit, xlimit, gt_pch_p_21gimple_statement_base))
> +    xlimit = xlimit->next;
> +
> +  /* All of the statements within the half-open interval [x..xlimit) have
> +     just been marked.  Iterate through the list, visiting their fields.  */
> +  while (x != xlimit)
> +    {
> +      gt_pch_n_15basic_block_def (x->bb);
> +      switch (gimple_statement_structure (&((*x))))
> +       {
> +       case GSS_BASE:
> +         break;
> +       case GSS_WITH_OPS:
> +         {
> +           gimple_statement_with_ops *stmt
> +             = static_cast <gimple_statement_with_ops *> (x);
> +           size_t num = (size_t)(stmt->num_ops);
> +           for (size_t i = 0; i != num; i++)
> +             gt_pch_n_9tree_node (stmt->op[i]);
> +         }
> +         break;
> +       case GSS_WITH_MEM_OPS_BASE:
> +         break;
> +       case GSS_WITH_MEM_OPS:
> +         {
> +           gimple_statement_with_memory_ops *stmt
> +             = static_cast <gimple_statement_with_memory_ops *> (x);
> +           size_t num = (size_t)(stmt->num_ops);
> +           for (size_t i = 0; i != num; i++)
> +             gt_pch_n_9tree_node (stmt->op[i]);
> +         }
> +         break;
> +       case GSS_CALL:
> +         {
> +           gimple_statement_call *stmt
> +             = static_cast <gimple_statement_call *> (x);
> +           gt_pch_n_15bitmap_head_def (stmt->call_used.vars);
> +           gt_pch_n_15bitmap_head_def (stmt->call_clobbered.vars);
> +           switch (stmt->subcode & GF_CALL_INTERNAL)
> +             {
> +             case 0:
> +               gt_pch_n_9tree_node (stmt->u.fntype);
> +               break;
> +             case GF_CALL_INTERNAL:
> +               break;
> +             default:
> +               break;
> +             }
> +           size_t num = (size_t)(stmt->num_ops);
> +           for (size_t i = 0; i != num; i++)
> +             gt_pch_n_9tree_node (stmt->op[i]);
> +         }
> +         break;
> +       case GSS_OMP:
> +         {
> +           gimple_statement_omp *stmt
> +             = static_cast <gimple_statement_omp *> (x);
> +           gt_pch_nx_gimple_statement_base (stmt->body);
> +         }
> +         break;
> +       case GSS_BIND:
> +         {
> +            gimple_statement_bind *stmt
> +             = static_cast <gimple_statement_bind *> (x);
> +           gt_pch_n_9tree_node (stmt->vars);
> +           gt_pch_n_9tree_node (stmt->block);
> +           gt_pch_nx_gimple_statement_base (stmt->body);
> +         }
> +         break;
> +       case GSS_CATCH:
> +         {
> +           gimple_statement_catch *stmt
> +             = static_cast <gimple_statement_catch *> (x);
> +           gt_pch_n_9tree_node (stmt->types);
> +           gt_pch_nx_gimple_statement_base (stmt->handler);
> +         }
> +         break;
> +       case GSS_EH_FILTER:
> +         {
> +           gimple_statement_eh_filter *stmt
> +             = static_cast <gimple_statement_eh_filter *> (x);
> +           gt_pch_n_9tree_node (stmt->types);
> +           gt_pch_nx_gimple_statement_base (stmt->failure);
> +         }
> +         break;
> +       case GSS_EH_MNT:
> +         {
> +           gimple_statement_eh_mnt *stmt
> +             = static_cast <gimple_statement_eh_mnt *> (x);
> +           gt_pch_n_9tree_node (stmt->fndecl);
> +         }
> +         break;
> +       case GSS_EH_ELSE:
> +         {
> +           gimple_statement_eh_else*stmt
> +             = static_cast <gimple_statement_eh_else *> (x);
> +           gt_pch_nx_gimple_statement_base (stmt->n_body);
> +           gt_pch_nx_gimple_statement_base (stmt->e_body);
> +         }
> +         break;
> +       case GSS_PHI:
> +         {
> +           gimple_statement_phi *stmt
> +             = static_cast <gimple_statement_phi *> (x);
> +           size_t num = (size_t)(stmt->nargs);
> +           gt_pch_n_9tree_node (stmt->result);
> +           for (size_t i = 0; i != num; i++)
> +             gt_pch_n_9tree_node (stmt->args[i].def);
> +         }
> +         break;
> +       case GSS_EH_CTRL:
> +         break;
> +       case GSS_TRY:
> +         {
> +           gimple_statement_try *stmt
> +             = static_cast <gimple_statement_try *> (x);
> +           gt_pch_nx_gimple_statement_base (stmt->eval);
> +           gt_pch_nx_gimple_statement_base (stmt->cleanup);
> +         }
> +         break;
> +       case GSS_WCE:
> +         {
> +           gimple_statement_wce *stmt
> +             = static_cast <gimple_statement_wce *> (x);
> +           gt_pch_nx_gimple_statement_base (stmt->cleanup);
> +         }
> +         break;
> +       case GSS_ASM:
> +         {
> +           gimple_statement_asm *stmt
> +             = static_cast <gimple_statement_asm *> (x);
> +           size_t num = (size_t)(stmt->num_ops);
> +           gt_pch_n_S (stmt->string);
> +           for (size_t i = 0; i != num; i++)
> +             gt_pch_n_9tree_node (stmt->op[i]);
> +         }
> +         break;
> +       case GSS_OMP_CRITICAL:
> +         {
> +           gimple_statement_omp_critical *stmt
> +             = static_cast <gimple_statement_omp_critical *> (x);
> +           gt_pch_nx_gimple_statement_base (stmt->body);
> +           gt_pch_n_9tree_node (stmt->name);
> +         }
> +         break;
> +       case GSS_OMP_FOR:
> +         {
> +           gimple_statement_omp_for *stmt
> +             = static_cast <gimple_statement_omp_for *> (x);
> +           size_t num = (size_t)(stmt->collapse);
> +           gt_pch_nx_gimple_statement_base (stmt->body);
> +           gt_pch_n_9tree_node (stmt->clauses);
> +           if (stmt->iter != NULL) {
> +             for (size_t i = 0; i != num; i++) {
> +               gt_pch_n_9tree_node (stmt->iter[i].index);
> +               gt_pch_n_9tree_node (stmt->iter[i].initial);
> +               gt_pch_n_9tree_node (stmt->iter[i].final);
> +               gt_pch_n_9tree_node (stmt->iter[i].incr);
> +             }
> +             gt_pch_note_object (stmt->iter, x,
> +                                 gt_pch_p_21gimple_statement_base);
> +           }
> +           gt_pch_nx_gimple_statement_base (stmt->pre_body);
> +         }
> +         break;
> +       case GSS_OMP_PARALLEL:
> +         {
> +           gimple_statement_omp_parallel *stmt
> +             = static_cast <gimple_statement_omp_parallel *> (x);
> +           gt_pch_nx_gimple_statement_base (stmt->body);
> +           gt_pch_n_9tree_node (stmt->clauses);
> +           gt_pch_n_9tree_node (stmt->child_fn);
> +           gt_pch_n_9tree_node (stmt->data_arg);
> +         }
> +         break;
> +       case GSS_OMP_TASK:
> +         {
> +           gimple_statement_omp_task *stmt
> +             = static_cast <gimple_statement_omp_task *> (x);
> +           gt_pch_nx_gimple_statement_base (stmt->body);
> +           gt_pch_n_9tree_node (stmt->clauses);
> +           gt_pch_n_9tree_node (stmt->child_fn);
> +           gt_pch_n_9tree_node (stmt->data_arg);
> +           gt_pch_n_9tree_node (stmt->copy_fn);
> +           gt_pch_n_9tree_node (stmt->arg_size);
> +           gt_pch_n_9tree_node (stmt->arg_align);
> +         }
> +         break;
> +       case GSS_OMP_SECTIONS:
> +         {
> +           gimple_statement_omp_sections *stmt
> +             = static_cast <gimple_statement_omp_sections *> (x);
> +           gt_pch_nx_gimple_statement_base (stmt->body);
> +           gt_pch_n_9tree_node (stmt->clauses);
> +           gt_pch_n_9tree_node (stmt->control);
> +         }
> +         break;
> +       case GSS_OMP_SINGLE:
> +         {
> +           gimple_statement_omp_single *stmt
> +             = static_cast <gimple_statement_omp_single *> (x);
> +           gt_pch_nx_gimple_statement_base (stmt->body);
> +           gt_pch_n_9tree_node (stmt->clauses);
> +         }
> +         break;
> +       case GSS_OMP_CONTINUE:
> +         {
> +           gimple_statement_omp_continue *stmt
> +             = static_cast <gimple_statement_omp_continue *> (x);
> +           gt_pch_n_9tree_node (stmt->control_def);
> +           gt_pch_n_9tree_node (stmt->control_use);
> +         }
> +         break;
> +       case GSS_OMP_ATOMIC_LOAD:
> +         {
> +           gimple_statement_omp_atomic_load *stmt
> +             = static_cast <gimple_statement_omp_atomic_load *> (x);
> +           gt_pch_n_9tree_node (stmt->rhs);
> +           gt_pch_n_9tree_node (stmt->lhs);
> +         }
> +         break;
> +       case GSS_OMP_ATOMIC_STORE:
> +         {
> +           gimple_statement_omp_atomic_store *stmt
> +             = static_cast <gimple_statement_omp_atomic_store *> (x);
> +           gt_pch_n_9tree_node (stmt->val);
> +         }
> +         break;
> +       case GSS_TRANSACTION:
> +         {
> +           gimple_statement_transaction *stmt
> +             = static_cast <gimple_statement_transaction *> (x);
> +           gt_pch_nx_gimple_statement_base (stmt->body);
> +           gt_pch_n_9tree_node (stmt->label);
> +         }
> +         break;
> +       default:
> +         break;
> +       }
> +      x = x->next;
> +    }
> +}
> +
> +void
> +gt_pch_nx (gimple gs, gt_pointer_operator op, void *cookie)
> +{
> +  op (&(gs->bb), cookie);
> +  op (&(gs->next), cookie);
> +  switch (gimple_statement_structure (gs))
> +    {
> +    case GSS_BASE:
> +      break;
> +    case GSS_WITH_OPS:
> +      {
> +       gimple_statement_with_ops *stmt
> +         = static_cast <gimple_statement_with_ops *> (gs);
> +       size_t num = (size_t)(stmt->num_ops);
> +       for (size_t i = 0; i != num; i++)
> +         op (&(stmt->op[i]), cookie);
> +      }
> +      break;
> +    case GSS_WITH_MEM_OPS_BASE:
> +      break;
> +    case GSS_WITH_MEM_OPS:
> +      {
> +       gimple_statement_with_memory_ops *stmt
> +         = static_cast <gimple_statement_with_memory_ops *> (gs);
> +       size_t num = (size_t)(stmt->num_ops);
> +       for (size_t i = 0; i != num; i++)
> +         op (&(stmt->op[i]), cookie);
> +      }
> +      break;
> +    case GSS_CALL:
> +      {
> +       gimple_statement_call *stmt
> +         = static_cast <gimple_statement_call *> (gs);
> +       size_t num = (size_t)(stmt->num_ops);
> +       op (&(stmt->call_used.vars), cookie);
> +       op (&(stmt->call_clobbered.vars), cookie);
> +       switch (stmt->subcode & GF_CALL_INTERNAL)
> +         {
> +         case 0:
> +           op (&(stmt->u.fntype), cookie);
> +           break;
> +         case GF_CALL_INTERNAL:
> +           break;
> +         default:
> +           break;
> +         }
> +       for (size_t i = 0; i != num; i++)
> +         op (&(stmt->op[i]), cookie);
> +      }
> +      break;
> +    case GSS_OMP:
> +      {
> +       gimple_statement_omp *stmt
> +         = static_cast <gimple_statement_omp *> (gs);
> +       op (&(stmt->body), cookie);
> +      }
> +      break;
> +    case GSS_BIND:
> +      {
> +       gimple_statement_bind *stmt
> +         = static_cast <gimple_statement_bind *> (gs);
> +       op (&(stmt->vars), cookie);
> +       op (&(stmt->block), cookie);
> +       op (&(stmt->body), cookie);
> +      }
> +      break;
> +    case GSS_CATCH:
> +      {
> +       gimple_statement_catch *stmt
> +         = static_cast <gimple_statement_catch *> (gs);
> +       op (&(stmt->types), cookie);
> +       op (&(stmt->handler), cookie);
> +      }
> +      break;
> +    case GSS_EH_FILTER:
> +      {
> +       gimple_statement_eh_filter *stmt
> +         = static_cast <gimple_statement_eh_filter *> (gs);
> +       op (&(stmt->types), cookie);
> +       op (&(stmt->failure), cookie);
> +      }
> +      break;
> +    case GSS_EH_MNT:
> +      {
> +       gimple_statement_eh_mnt *stmt
> +         = static_cast <gimple_statement_eh_mnt *> (gs);
> +       op (&(stmt->fndecl), cookie);
> +      }
> +      break;
> +    case GSS_EH_ELSE:
> +      {
> +       gimple_statement_eh_else*stmt
> +         = static_cast <gimple_statement_eh_else *> (gs);
> +       op (&(stmt->n_body), cookie);
> +       op (&(stmt->e_body), cookie);
> +      }
> +      break;
> +    case GSS_PHI:
> +      {
> +       gimple_statement_phi *stmt
> +         = static_cast <gimple_statement_phi *> (gs);
> +       size_t num = (size_t)(stmt->nargs);
> +       op (&(stmt->result), cookie);
> +       for (size_t i = 0; i != num; i++)
> +         op (&(stmt->args[i].def), cookie);
> +      }
> +      break;
> +    case GSS_EH_CTRL:
> +      break;
> +    case GSS_TRY:
> +      {
> +       gimple_statement_try *stmt
> +         = static_cast <gimple_statement_try *> (gs);
> +       op (&(stmt->eval), cookie);
> +       op (&(stmt->cleanup), cookie);
> +      }
> +      break;
> +    case GSS_WCE:
> +      {
> +       gimple_statement_wce *stmt
> +         = static_cast <gimple_statement_wce *> (gs);
> +       op (&(stmt->cleanup), cookie);
> +      }
> +      break;
> +    case GSS_ASM:
> +      {
> +       gimple_statement_asm *stmt
> +         = static_cast <gimple_statement_asm *> (gs);
> +       size_t num = (size_t)(stmt->num_ops);
> +       op (&(stmt->string), cookie);
> +       for (size_t i = 0; i != num; i++)
> +         op (&(stmt->op[i]), cookie);
> +      }
> +      break;
> +    case GSS_OMP_CRITICAL:
> +      {
> +       gimple_statement_omp_critical *stmt
> +         = static_cast <gimple_statement_omp_critical *> (gs);
> +       op (&(stmt->body), cookie);
> +       op (&(stmt->name), cookie);
> +      }
> +      break;
> +    case GSS_OMP_FOR:
> +      {
> +       gimple_statement_omp_for *stmt
> +         = static_cast <gimple_statement_omp_for *> (gs);
> +       size_t num = (size_t)(stmt->collapse);
> +       op (&(stmt->body), cookie);
> +       op (&(stmt->clauses), cookie);
> +       if (stmt->iter != NULL) {
> +         for (size_t i = 0; i != num; i++) {
> +           op (&(stmt->iter[i].index), cookie);
> +           op (&(stmt->iter[i].initial), cookie);
> +           op (&(stmt->iter[i].final), cookie);
> +           op (&(stmt->iter[i].incr), cookie);
> +         }
> +         op (&(stmt->iter), cookie);
> +       }
> +       op (&(stmt->pre_body), cookie);
> +      }
> +      break;
> +    case GSS_OMP_PARALLEL:
> +      {
> +       gimple_statement_omp_parallel *stmt
> +         = static_cast <gimple_statement_omp_parallel *> (gs);
> +       op (&(stmt->body), cookie);
> +       op (&(stmt->clauses), cookie);
> +       op (&(stmt->child_fn), cookie);
> +       op (&(stmt->data_arg), cookie);
> +      }
> +      break;
> +    case GSS_OMP_TASK:
> +      {
> +       gimple_statement_omp_task *stmt
> +         = static_cast <gimple_statement_omp_task *> (gs);
> +       op (&(stmt->body), cookie);
> +       op (&(stmt->clauses), cookie);
> +       op (&(stmt->child_fn), cookie);
> +       op (&(stmt->data_arg), cookie);
> +       op (&(stmt->copy_fn), cookie);
> +       op (&(stmt->arg_size), cookie);
> +       op (&(stmt->arg_align), cookie);
> +      }
> +      break;
> +    case GSS_OMP_SECTIONS:
> +      {
> +       gimple_statement_omp_sections *stmt
> +         = static_cast <gimple_statement_omp_sections *> (gs);
> +       op (&(stmt->body), cookie);
> +       op (&(stmt->clauses), cookie);
> +       op (&(stmt->control), cookie);
> +      }
> +      break;
> +    case GSS_OMP_SINGLE:
> +      {
> +       gimple_statement_omp_single *stmt
> +         = static_cast <gimple_statement_omp_single *> (gs);
> +       op (&(stmt->body), cookie);
> +       op (&(stmt->clauses), cookie);
> +      }
> +      break;
> +    case GSS_OMP_CONTINUE:
> +      {
> +       gimple_statement_omp_continue *stmt
> +         = static_cast <gimple_statement_omp_continue *> (gs);
> +       op (&(stmt->control_def), cookie);
> +       op (&(stmt->control_use), cookie);
> +      }
> +      break;
> +    case GSS_OMP_ATOMIC_LOAD:
> +      {
> +       gimple_statement_omp_atomic_load *stmt
> +         = static_cast <gimple_statement_omp_atomic_load *> (gs);
> +       op (&(stmt->rhs), cookie);
> +       op (&(stmt->lhs), cookie);
> +      }
> +      break;
> +    case GSS_OMP_ATOMIC_STORE:
> +      {
> +       gimple_statement_omp_atomic_store *stmt
> +         = static_cast <gimple_statement_omp_atomic_store *> (gs);
> +       op (&(stmt->val), cookie);
> +      }
> +      break;
> +    case GSS_TRANSACTION:
> +      {
> +       gimple_statement_transaction *stmt
> +         = static_cast <gimple_statement_transaction *> (gs);
> +       op (&(stmt->body), cookie);
> +       op (&(stmt->label), cookie);
> +      }
> +      break;
> +    default:
> +      break;
> +    }
> +}
> +
> +
>  #include "gt-gimple.h"
> diff --git a/gcc/gimple.h b/gcc/gimple.h
> index daab54e..9b428eb 100644
> --- a/gcc/gimple.h
> +++ b/gcc/gimple.h
> @@ -222,6 +222,12 @@ struct GTY((user)) gimple_statement_base {
>    gimple GTY((skip)) prev;
>  };
>
> +/* GTY((user)) hooks for gimple, called once per-traversal.  */
> +void gt_ggc_mx (gimple gs);
> +void gt_pch_nx (gimple gs);
> +void gt_pch_nx (gimple gs, gt_pointer_operator op, void *cookie);
> +
> +
>
>  /* Base structure for tuples with operands.  */
>
> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
> index af8685c..185c072 100644
> --- a/gcc/tree-cfg.c
> +++ b/gcc/tree-cfg.c
> @@ -8291,7 +8291,6 @@ make_pass_warn_unused_result (gcc::context *ctxt)
>  /* Garbage collection support for edge_def.  */
>
>  extern void gt_ggc_mx (tree&);
> -extern void gt_ggc_mx (gimple&);
>  extern void gt_ggc_mx (rtx&);
>  extern void gt_ggc_mx (basic_block&);
>
> @@ -8302,7 +8301,7 @@ gt_ggc_mx (edge_def *e)
>    gt_ggc_mx (e->src);
>    gt_ggc_mx (e->dest);
>    if (current_ir_type () == IR_GIMPLE)
> -    gt_ggc_mx (e->insns.g);
> +    gt_ggc_mx_gimple_statement_base (e->insns.g);
>    else
>      gt_ggc_mx (e->insns.r);
>    gt_ggc_mx (block);
> @@ -8311,7 +8310,6 @@ gt_ggc_mx (edge_def *e)
>  /* PCH support for edge_def.  */
>
>  extern void gt_pch_nx (tree&);
> -extern void gt_pch_nx (gimple&);
>  extern void gt_pch_nx (rtx&);
>  extern void gt_pch_nx (basic_block&);
>
> @@ -8322,7 +8320,7 @@ gt_pch_nx (edge_def *e)
>    gt_pch_nx (e->src);
>    gt_pch_nx (e->dest);
>    if (current_ir_type () == IR_GIMPLE)
> -    gt_pch_nx (e->insns.g);
> +    gt_pch_nx_gimple_statement_base (e->insns.g);
>    else
>      gt_pch_nx (e->insns.r);
>    gt_pch_nx (block);
> --
> 1.7.11.7
>
Richard Guenther - Aug. 30, 2013, 8:09 a.m.
On Thu, Aug 29, 2013 at 9:44 PM, Steven Bosscher <stevenb.gcc@gmail.com> wrote:
> On Thu, Aug 29, 2013 at 6:20 PM, David Malcolm <dmalcolm@redhat.com> wrote:
>>         * gimple.c (gt_ggc_mx (gimple)): New, as required by GTY((user)).
>>         (gt_pch_nx (gimple)): Likewise.
>
> GIMPLE isn't supposed to end up in a PCH. Can you please make this
> function simply call gcc_unreachable()?
>
> FWIW 1: I really think all these hand-written markers aren't a good
> idea, we should really figure out a way to have automatic marker
> function generators, something less complex than gengtype, of course.
> But to have all these calls to the type-mangled marker functions
> (gt_pch_n_9tree_node, etc.) is going to be a problem in the long term.
>
> It seems to me that the first step in all these conversions to
> hand-written markers should be to make gengtype spit out the marker
> functions *without* the type name mangling, i.e. all marker functions
> should just be gt_ggc_mx(type) / gt_pch_nx(type).

Yes, the original idea was that gengtype would do that.  For things we like
to optimize the GTY((user)) thing would tell it that we do provide the markers.
Like when you want to look through a non-GCed intermediate object.  Or
for things like GTY((chain)) stuff that doesn't really work if you have multiple
chains (without clever GTY((skip))s...).

The lack of the unmangled overloads is annoying :/  IIRC Diego halfway completed
the transition to unmangled overloads / specializations?

Richard.

> Ciao!
> Steven
Richard Guenther - Aug. 30, 2013, 8:40 a.m.
On Thu, Aug 29, 2013 at 6:20 PM, David Malcolm <dmalcolm@redhat.com> wrote:
>         * gimple.c (gt_ggc_mx (gimple)): New, as required by GTY((user)).
>         (gt_pch_nx (gimple)): Likewise.
>         (gt_pch_nx (gimple, gt_pointer_operator, void *)): Likewise.
>         * gimple.h  (gt_ggc_mx (gimple)): Declare.
>         (gt_pch_nx (gimple)): Declare.
>         (gt_pch_nx (gimple, gt_pointer_operator, void *)): Declare.
>         * tree-cfg.c (ggc_mx (gimple&)): Remove declaration, as this
>         collides with the function that GTY((user)) expects.
>         (gt_ggc_mx (edge_def *)): Replace call to gt_ggc_mx on the
>         gimple with gt_ggc_mx_gimple_statement_base: in the
>         pre-GTY((user)) world, "gt_ggc_mx" was the function to be called
>         on a possibly NULL pointed to check if needed marking and if so
>         to traverse its fields.  In the GTY((user)) world, "gt_ggc_mx"
>         is the function to be called on non-NULL objects immediately *after*
>         they have been marked: it does not mark the object itself.
>         (gt_pch_nx (gimple&)): Remove declaration.
>         (gt_pch_nx (edge_def *)): Update as per the mx hook.

Btw, this shows that gimple isn't a true C++ hierarchy - because of GTY
you can only ever use 'gimple' pointers, not more specialized ones
like gimple_phi as you are missing the GTY machinery for them.

I'm not 100% convinced that we should do all this at this point without
getting a better hand on the gengtype issues (it's partial transition to
the C++ world of GCC)

> ---
>  gcc/gimple.c   | 743 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  gcc/gimple.h   |   6 +
>  gcc/tree-cfg.c |   6 +-
>  3 files changed, 751 insertions(+), 4 deletions(-)
>
> diff --git a/gcc/gimple.c b/gcc/gimple.c
> index 1ad36d1..dd99cda 100644
> --- a/gcc/gimple.c
> +++ b/gcc/gimple.c
> @@ -4338,4 +4338,747 @@ build_type_cast (tree to_type, gimple op, enum ssa_mode mode)
>    return build_type_cast (to_type, gimple_assign_lhs (op), mode);
>  }
>
> +void
> +gt_ggc_mx (gimple gs)
> +{
> +  gimple x = gs;
> +  /* Emulation of the "chain_next" GTY attribute.
> +
> +     gs has already been marked.
> +     Iterate the chain of next statements, marking until we reach one that
> +     has already been marked, or NULL.   */
> +  gimple xlimit = gs->next;
> +  while (ggc_test_and_set_mark (xlimit))
> +    xlimit = xlimit->next;
> +
> +  /* All of the statements within the half-open interval [x..xlimit) have
> +     just been marked.  Iterate through the list, visiting their fields.  */
> +  while (x != xlimit)
> +    {
> +      gt_ggc_m_15basic_block_def (x->bb);
> +      switch (gimple_statement_structure (&((*x))))
> +       {
> +       case GSS_BASE:
> +         break;
> +       case GSS_WITH_OPS:
> +         {
> +           gimple_statement_with_ops *stmt
> +             = static_cast <gimple_statement_with_ops *> (x);
> +           size_t num = (size_t)(stmt->num_ops);
> +           for (size_t i = 0; i != num; i++)
> +             gt_ggc_m_9tree_node (stmt->op[i]);
> +         }
> +         break;
> +       case GSS_WITH_MEM_OPS_BASE:
> +         break;
> +       case GSS_WITH_MEM_OPS:
> +         {
> +           gimple_statement_with_memory_ops *stmt
> +             = static_cast <gimple_statement_with_memory_ops *> (x);
> +           size_t num = (size_t)(stmt->num_ops);
> +           for (size_t i = 0; i != num; i++)
> +             gt_ggc_m_9tree_node (stmt->op[i]);
> +         }
> +         break;
> +       case GSS_CALL:
> +         {
> +           gimple_statement_call *stmt
> +             = static_cast <gimple_statement_call *> (x);
> +           gt_ggc_m_15bitmap_head_def (stmt->call_used.vars);
> +           gt_ggc_m_15bitmap_head_def (stmt->call_clobbered.vars);
> +           switch (stmt->subcode & GF_CALL_INTERNAL)
> +             {
> +             case 0:
> +               gt_ggc_m_9tree_node (stmt->u.fntype);
> +               break;
> +             case GF_CALL_INTERNAL:
> +               break;
> +             default:
> +               break;
> +             }
> +           size_t num = (size_t)(stmt->num_ops);
> +           for (size_t i = 0; i != num; i++)
> +             gt_ggc_m_9tree_node (stmt->op[i]);
> +         }
> +         break;
> +       case GSS_OMP:
> +         {
> +           gimple_statement_omp *stmt
> +             = static_cast <gimple_statement_omp *> (x);
> +           gt_ggc_mx_gimple_statement_base (stmt->body);
> +         }
> +         break;
> +       case GSS_BIND:
> +         {
> +            gimple_statement_bind *stmt
> +             = static_cast <gimple_statement_bind *> (x);
> +           gt_ggc_m_9tree_node (stmt->vars);
> +           gt_ggc_m_9tree_node (stmt->block);
> +           gt_ggc_mx_gimple_statement_base (stmt->body);
> +         }
> +         break;
> +       case GSS_CATCH:
> +         {
> +           gimple_statement_catch *stmt
> +             = static_cast <gimple_statement_catch *> (x);
> +           gt_ggc_m_9tree_node (stmt->types);
> +           gt_ggc_mx_gimple_statement_base (stmt->handler);
> +         }
> +         break;
> +       case GSS_EH_FILTER:
> +         {
> +           gimple_statement_eh_filter *stmt
> +             = static_cast <gimple_statement_eh_filter *> (x);
> +           gt_ggc_m_9tree_node (stmt->types);
> +           gt_ggc_mx_gimple_statement_base (stmt->failure);
> +         }
> +         break;
> +       case GSS_EH_MNT:
> +         {
> +           gimple_statement_eh_mnt *stmt
> +             = static_cast <gimple_statement_eh_mnt *> (x);
> +           gt_ggc_m_9tree_node (stmt->fndecl);
> +         }
> +         break;
> +       case GSS_EH_ELSE:
> +         {
> +           gimple_statement_eh_else*stmt
> +             = static_cast <gimple_statement_eh_else *> (x);
> +           gt_ggc_mx_gimple_statement_base (stmt->n_body);
> +           gt_ggc_mx_gimple_statement_base (stmt->e_body);
> +         }
> +         break;
> +       case GSS_PHI:
> +         {
> +           gimple_statement_phi *stmt
> +             = static_cast <gimple_statement_phi *> (x);
> +           size_t num = (size_t)(stmt->nargs);
> +           gt_ggc_m_9tree_node (stmt->result);
> +           for (size_t i = 0; i != num; i++)
> +             gt_ggc_m_9tree_node (stmt->args[i].def);
> +         }
> +         break;
> +       case GSS_EH_CTRL:
> +         break;
> +       case GSS_TRY:
> +         {
> +           gimple_statement_try *stmt
> +             = static_cast <gimple_statement_try *> (x);
> +           gt_ggc_mx_gimple_statement_base (stmt->eval);
> +           gt_ggc_mx_gimple_statement_base (stmt->cleanup);
> +         }
> +         break;
> +       case GSS_WCE:
> +         {
> +           gimple_statement_wce *stmt
> +             = static_cast <gimple_statement_wce *> (x);
> +           gt_ggc_mx_gimple_statement_base (stmt->cleanup);
> +         }
> +         break;
> +       case GSS_ASM:
> +         {
> +           gimple_statement_asm *stmt
> +             = static_cast <gimple_statement_asm *> (x);
> +           size_t num = (size_t)(stmt->num_ops);
> +           gt_ggc_m_S (stmt->string);
> +           for (size_t i = 0; i != num; i++)
> +             gt_ggc_m_9tree_node (stmt->op[i]);
> +         }
> +         break;
> +       case GSS_OMP_CRITICAL:
> +         {
> +           gimple_statement_omp_critical *stmt
> +             = static_cast <gimple_statement_omp_critical *> (x);
> +           gt_ggc_mx_gimple_statement_base (stmt->body);
> +           gt_ggc_m_9tree_node (stmt->name);
> +         }
> +         break;
> +       case GSS_OMP_FOR:
> +         {
> +           gimple_statement_omp_for *stmt
> +             = static_cast <gimple_statement_omp_for *> (x);
> +           size_t num = (size_t)(stmt->collapse);
> +           gt_ggc_mx_gimple_statement_base (stmt->body);
> +           gt_ggc_m_9tree_node (stmt->clauses);
> +           if (stmt->iter != NULL) {
> +             for (size_t i = 0; i != num; i++) {
> +               gt_ggc_m_9tree_node (stmt->iter[i].index);
> +               gt_ggc_m_9tree_node (stmt->iter[i].initial);
> +               gt_ggc_m_9tree_node (stmt->iter[i].final);
> +               gt_ggc_m_9tree_node (stmt->iter[i].incr);
> +             }
> +             ggc_mark (stmt->iter);
> +           }
> +           gt_ggc_mx_gimple_statement_base (stmt->pre_body);
> +         }
> +         break;
> +       case GSS_OMP_PARALLEL:
> +         {
> +           gimple_statement_omp_parallel *stmt
> +             = static_cast <gimple_statement_omp_parallel *> (x);
> +           gt_ggc_mx_gimple_statement_base (stmt->body);
> +           gt_ggc_m_9tree_node (stmt->clauses);
> +           gt_ggc_m_9tree_node (stmt->child_fn);
> +           gt_ggc_m_9tree_node (stmt->data_arg);
> +         }
> +         break;
> +       case GSS_OMP_TASK:
> +         {
> +           gimple_statement_omp_task *stmt
> +             = static_cast <gimple_statement_omp_task *> (x);
> +           gt_ggc_mx_gimple_statement_base (stmt->body);
> +           gt_ggc_m_9tree_node (stmt->clauses);
> +           gt_ggc_m_9tree_node (stmt->child_fn);
> +           gt_ggc_m_9tree_node (stmt->data_arg);
> +           gt_ggc_m_9tree_node (stmt->copy_fn);
> +           gt_ggc_m_9tree_node (stmt->arg_size);
> +           gt_ggc_m_9tree_node (stmt->arg_align);
> +         }
> +         break;
> +       case GSS_OMP_SECTIONS:
> +         {
> +           gimple_statement_omp_sections *stmt
> +             = static_cast <gimple_statement_omp_sections *> (x);
> +           gt_ggc_mx_gimple_statement_base (stmt->body);
> +           gt_ggc_m_9tree_node (stmt->clauses);
> +           gt_ggc_m_9tree_node (stmt->control);
> +         }
> +         break;
> +       case GSS_OMP_SINGLE:
> +         {
> +           gimple_statement_omp_single *stmt
> +             = static_cast <gimple_statement_omp_single *> (x);
> +           gt_ggc_mx_gimple_statement_base (stmt->body);
> +           gt_ggc_m_9tree_node (stmt->clauses);
> +         }
> +         break;
> +       case GSS_OMP_CONTINUE:
> +         {
> +           gimple_statement_omp_continue *stmt
> +             = static_cast <gimple_statement_omp_continue *> (x);
> +           gt_ggc_m_9tree_node (stmt->control_def);
> +           gt_ggc_m_9tree_node (stmt->control_use);
> +         }
> +         break;
> +       case GSS_OMP_ATOMIC_LOAD:
> +         {
> +           gimple_statement_omp_atomic_load *stmt
> +             = static_cast <gimple_statement_omp_atomic_load *> (x);
> +           gt_ggc_m_9tree_node (stmt->rhs);
> +           gt_ggc_m_9tree_node (stmt->lhs);
> +         }
> +         break;
> +       case GSS_OMP_ATOMIC_STORE:
> +         {
> +           gimple_statement_omp_atomic_store *stmt
> +             = static_cast <gimple_statement_omp_atomic_store *> (x);
> +           gt_ggc_m_9tree_node (stmt->val);
> +         }
> +         break;
> +       case GSS_TRANSACTION:
> +         {
> +           gimple_statement_transaction *stmt
> +             = static_cast <gimple_statement_transaction *> (x);
> +           gt_ggc_mx_gimple_statement_base (stmt->body);
> +           gt_ggc_m_9tree_node (stmt->label);
> +         }
> +         break;
> +       default:
> +         break;
> +       }
> +      x = x->next;
> +    }
> +}
> +
> +void
> +gt_pch_nx (gimple gs)
> +{
> +  gimple x = gs;
> +  /* Emulation of the "chain_next" GTY attribute.
> +
> +     gs has already been marked.
> +     Iterate the chain of next statements, marking until we reach one that
> +     has already been marked, or NULL.   */
> +  gimple xlimit = gs->next;
> +  while (gt_pch_note_object (xlimit, xlimit, gt_pch_p_21gimple_statement_base))
> +    xlimit = xlimit->next;
> +
> +  /* All of the statements within the half-open interval [x..xlimit) have
> +     just been marked.  Iterate through the list, visiting their fields.  */
> +  while (x != xlimit)
> +    {
> +      gt_pch_n_15basic_block_def (x->bb);
> +      switch (gimple_statement_structure (&((*x))))
> +       {
> +       case GSS_BASE:
> +         break;
> +       case GSS_WITH_OPS:
> +         {
> +           gimple_statement_with_ops *stmt
> +             = static_cast <gimple_statement_with_ops *> (x);
> +           size_t num = (size_t)(stmt->num_ops);
> +           for (size_t i = 0; i != num; i++)
> +             gt_pch_n_9tree_node (stmt->op[i]);
> +         }
> +         break;
> +       case GSS_WITH_MEM_OPS_BASE:
> +         break;
> +       case GSS_WITH_MEM_OPS:
> +         {
> +           gimple_statement_with_memory_ops *stmt
> +             = static_cast <gimple_statement_with_memory_ops *> (x);
> +           size_t num = (size_t)(stmt->num_ops);
> +           for (size_t i = 0; i != num; i++)
> +             gt_pch_n_9tree_node (stmt->op[i]);
> +         }
> +         break;
> +       case GSS_CALL:
> +         {
> +           gimple_statement_call *stmt
> +             = static_cast <gimple_statement_call *> (x);
> +           gt_pch_n_15bitmap_head_def (stmt->call_used.vars);
> +           gt_pch_n_15bitmap_head_def (stmt->call_clobbered.vars);
> +           switch (stmt->subcode & GF_CALL_INTERNAL)
> +             {
> +             case 0:
> +               gt_pch_n_9tree_node (stmt->u.fntype);
> +               break;
> +             case GF_CALL_INTERNAL:
> +               break;
> +             default:
> +               break;
> +             }
> +           size_t num = (size_t)(stmt->num_ops);
> +           for (size_t i = 0; i != num; i++)
> +             gt_pch_n_9tree_node (stmt->op[i]);
> +         }
> +         break;
> +       case GSS_OMP:
> +         {
> +           gimple_statement_omp *stmt
> +             = static_cast <gimple_statement_omp *> (x);
> +           gt_pch_nx_gimple_statement_base (stmt->body);
> +         }
> +         break;
> +       case GSS_BIND:
> +         {
> +            gimple_statement_bind *stmt
> +             = static_cast <gimple_statement_bind *> (x);
> +           gt_pch_n_9tree_node (stmt->vars);
> +           gt_pch_n_9tree_node (stmt->block);
> +           gt_pch_nx_gimple_statement_base (stmt->body);
> +         }
> +         break;
> +       case GSS_CATCH:
> +         {
> +           gimple_statement_catch *stmt
> +             = static_cast <gimple_statement_catch *> (x);
> +           gt_pch_n_9tree_node (stmt->types);
> +           gt_pch_nx_gimple_statement_base (stmt->handler);
> +         }
> +         break;
> +       case GSS_EH_FILTER:
> +         {
> +           gimple_statement_eh_filter *stmt
> +             = static_cast <gimple_statement_eh_filter *> (x);
> +           gt_pch_n_9tree_node (stmt->types);
> +           gt_pch_nx_gimple_statement_base (stmt->failure);
> +         }
> +         break;
> +       case GSS_EH_MNT:
> +         {
> +           gimple_statement_eh_mnt *stmt
> +             = static_cast <gimple_statement_eh_mnt *> (x);
> +           gt_pch_n_9tree_node (stmt->fndecl);
> +         }
> +         break;
> +       case GSS_EH_ELSE:
> +         {
> +           gimple_statement_eh_else*stmt
> +             = static_cast <gimple_statement_eh_else *> (x);
> +           gt_pch_nx_gimple_statement_base (stmt->n_body);
> +           gt_pch_nx_gimple_statement_base (stmt->e_body);
> +         }
> +         break;
> +       case GSS_PHI:
> +         {
> +           gimple_statement_phi *stmt
> +             = static_cast <gimple_statement_phi *> (x);
> +           size_t num = (size_t)(stmt->nargs);
> +           gt_pch_n_9tree_node (stmt->result);
> +           for (size_t i = 0; i != num; i++)
> +             gt_pch_n_9tree_node (stmt->args[i].def);
> +         }
> +         break;
> +       case GSS_EH_CTRL:
> +         break;
> +       case GSS_TRY:
> +         {
> +           gimple_statement_try *stmt
> +             = static_cast <gimple_statement_try *> (x);
> +           gt_pch_nx_gimple_statement_base (stmt->eval);
> +           gt_pch_nx_gimple_statement_base (stmt->cleanup);
> +         }
> +         break;
> +       case GSS_WCE:
> +         {
> +           gimple_statement_wce *stmt
> +             = static_cast <gimple_statement_wce *> (x);
> +           gt_pch_nx_gimple_statement_base (stmt->cleanup);
> +         }
> +         break;
> +       case GSS_ASM:
> +         {
> +           gimple_statement_asm *stmt
> +             = static_cast <gimple_statement_asm *> (x);
> +           size_t num = (size_t)(stmt->num_ops);
> +           gt_pch_n_S (stmt->string);
> +           for (size_t i = 0; i != num; i++)
> +             gt_pch_n_9tree_node (stmt->op[i]);
> +         }
> +         break;
> +       case GSS_OMP_CRITICAL:
> +         {
> +           gimple_statement_omp_critical *stmt
> +             = static_cast <gimple_statement_omp_critical *> (x);
> +           gt_pch_nx_gimple_statement_base (stmt->body);
> +           gt_pch_n_9tree_node (stmt->name);
> +         }
> +         break;
> +       case GSS_OMP_FOR:
> +         {
> +           gimple_statement_omp_for *stmt
> +             = static_cast <gimple_statement_omp_for *> (x);
> +           size_t num = (size_t)(stmt->collapse);
> +           gt_pch_nx_gimple_statement_base (stmt->body);
> +           gt_pch_n_9tree_node (stmt->clauses);
> +           if (stmt->iter != NULL) {
> +             for (size_t i = 0; i != num; i++) {
> +               gt_pch_n_9tree_node (stmt->iter[i].index);
> +               gt_pch_n_9tree_node (stmt->iter[i].initial);
> +               gt_pch_n_9tree_node (stmt->iter[i].final);
> +               gt_pch_n_9tree_node (stmt->iter[i].incr);
> +             }
> +             gt_pch_note_object (stmt->iter, x,
> +                                 gt_pch_p_21gimple_statement_base);
> +           }
> +           gt_pch_nx_gimple_statement_base (stmt->pre_body);
> +         }
> +         break;
> +       case GSS_OMP_PARALLEL:
> +         {
> +           gimple_statement_omp_parallel *stmt
> +             = static_cast <gimple_statement_omp_parallel *> (x);
> +           gt_pch_nx_gimple_statement_base (stmt->body);
> +           gt_pch_n_9tree_node (stmt->clauses);
> +           gt_pch_n_9tree_node (stmt->child_fn);
> +           gt_pch_n_9tree_node (stmt->data_arg);
> +         }
> +         break;
> +       case GSS_OMP_TASK:
> +         {
> +           gimple_statement_omp_task *stmt
> +             = static_cast <gimple_statement_omp_task *> (x);
> +           gt_pch_nx_gimple_statement_base (stmt->body);
> +           gt_pch_n_9tree_node (stmt->clauses);
> +           gt_pch_n_9tree_node (stmt->child_fn);
> +           gt_pch_n_9tree_node (stmt->data_arg);
> +           gt_pch_n_9tree_node (stmt->copy_fn);
> +           gt_pch_n_9tree_node (stmt->arg_size);
> +           gt_pch_n_9tree_node (stmt->arg_align);
> +         }
> +         break;
> +       case GSS_OMP_SECTIONS:
> +         {
> +           gimple_statement_omp_sections *stmt
> +             = static_cast <gimple_statement_omp_sections *> (x);
> +           gt_pch_nx_gimple_statement_base (stmt->body);
> +           gt_pch_n_9tree_node (stmt->clauses);
> +           gt_pch_n_9tree_node (stmt->control);
> +         }
> +         break;
> +       case GSS_OMP_SINGLE:
> +         {
> +           gimple_statement_omp_single *stmt
> +             = static_cast <gimple_statement_omp_single *> (x);
> +           gt_pch_nx_gimple_statement_base (stmt->body);
> +           gt_pch_n_9tree_node (stmt->clauses);
> +         }
> +         break;
> +       case GSS_OMP_CONTINUE:
> +         {
> +           gimple_statement_omp_continue *stmt
> +             = static_cast <gimple_statement_omp_continue *> (x);
> +           gt_pch_n_9tree_node (stmt->control_def);
> +           gt_pch_n_9tree_node (stmt->control_use);
> +         }
> +         break;
> +       case GSS_OMP_ATOMIC_LOAD:
> +         {
> +           gimple_statement_omp_atomic_load *stmt
> +             = static_cast <gimple_statement_omp_atomic_load *> (x);
> +           gt_pch_n_9tree_node (stmt->rhs);
> +           gt_pch_n_9tree_node (stmt->lhs);
> +         }
> +         break;
> +       case GSS_OMP_ATOMIC_STORE:
> +         {
> +           gimple_statement_omp_atomic_store *stmt
> +             = static_cast <gimple_statement_omp_atomic_store *> (x);
> +           gt_pch_n_9tree_node (stmt->val);
> +         }
> +         break;
> +       case GSS_TRANSACTION:
> +         {
> +           gimple_statement_transaction *stmt
> +             = static_cast <gimple_statement_transaction *> (x);
> +           gt_pch_nx_gimple_statement_base (stmt->body);
> +           gt_pch_n_9tree_node (stmt->label);
> +         }
> +         break;
> +       default:
> +         break;
> +       }
> +      x = x->next;
> +    }
> +}
> +
> +void
> +gt_pch_nx (gimple gs, gt_pointer_operator op, void *cookie)
> +{
> +  op (&(gs->bb), cookie);
> +  op (&(gs->next), cookie);
> +  switch (gimple_statement_structure (gs))
> +    {
> +    case GSS_BASE:
> +      break;
> +    case GSS_WITH_OPS:
> +      {
> +       gimple_statement_with_ops *stmt
> +         = static_cast <gimple_statement_with_ops *> (gs);
> +       size_t num = (size_t)(stmt->num_ops);
> +       for (size_t i = 0; i != num; i++)
> +         op (&(stmt->op[i]), cookie);
> +      }
> +      break;
> +    case GSS_WITH_MEM_OPS_BASE:
> +      break;
> +    case GSS_WITH_MEM_OPS:
> +      {
> +       gimple_statement_with_memory_ops *stmt
> +         = static_cast <gimple_statement_with_memory_ops *> (gs);
> +       size_t num = (size_t)(stmt->num_ops);
> +       for (size_t i = 0; i != num; i++)
> +         op (&(stmt->op[i]), cookie);
> +      }
> +      break;
> +    case GSS_CALL:
> +      {
> +       gimple_statement_call *stmt
> +         = static_cast <gimple_statement_call *> (gs);
> +       size_t num = (size_t)(stmt->num_ops);
> +       op (&(stmt->call_used.vars), cookie);
> +       op (&(stmt->call_clobbered.vars), cookie);
> +       switch (stmt->subcode & GF_CALL_INTERNAL)
> +         {
> +         case 0:
> +           op (&(stmt->u.fntype), cookie);
> +           break;
> +         case GF_CALL_INTERNAL:
> +           break;
> +         default:
> +           break;
> +         }
> +       for (size_t i = 0; i != num; i++)
> +         op (&(stmt->op[i]), cookie);
> +      }
> +      break;
> +    case GSS_OMP:
> +      {
> +       gimple_statement_omp *stmt
> +         = static_cast <gimple_statement_omp *> (gs);
> +       op (&(stmt->body), cookie);
> +      }
> +      break;
> +    case GSS_BIND:
> +      {
> +       gimple_statement_bind *stmt
> +         = static_cast <gimple_statement_bind *> (gs);
> +       op (&(stmt->vars), cookie);
> +       op (&(stmt->block), cookie);
> +       op (&(stmt->body), cookie);
> +      }
> +      break;
> +    case GSS_CATCH:
> +      {
> +       gimple_statement_catch *stmt
> +         = static_cast <gimple_statement_catch *> (gs);
> +       op (&(stmt->types), cookie);
> +       op (&(stmt->handler), cookie);
> +      }
> +      break;
> +    case GSS_EH_FILTER:
> +      {
> +       gimple_statement_eh_filter *stmt
> +         = static_cast <gimple_statement_eh_filter *> (gs);
> +       op (&(stmt->types), cookie);
> +       op (&(stmt->failure), cookie);
> +      }
> +      break;
> +    case GSS_EH_MNT:
> +      {
> +       gimple_statement_eh_mnt *stmt
> +         = static_cast <gimple_statement_eh_mnt *> (gs);
> +       op (&(stmt->fndecl), cookie);
> +      }
> +      break;
> +    case GSS_EH_ELSE:
> +      {
> +       gimple_statement_eh_else*stmt
> +         = static_cast <gimple_statement_eh_else *> (gs);
> +       op (&(stmt->n_body), cookie);
> +       op (&(stmt->e_body), cookie);
> +      }
> +      break;
> +    case GSS_PHI:
> +      {
> +       gimple_statement_phi *stmt
> +         = static_cast <gimple_statement_phi *> (gs);
> +       size_t num = (size_t)(stmt->nargs);
> +       op (&(stmt->result), cookie);
> +       for (size_t i = 0; i != num; i++)
> +         op (&(stmt->args[i].def), cookie);
> +      }
> +      break;
> +    case GSS_EH_CTRL:
> +      break;
> +    case GSS_TRY:
> +      {
> +       gimple_statement_try *stmt
> +         = static_cast <gimple_statement_try *> (gs);
> +       op (&(stmt->eval), cookie);
> +       op (&(stmt->cleanup), cookie);
> +      }
> +      break;
> +    case GSS_WCE:
> +      {
> +       gimple_statement_wce *stmt
> +         = static_cast <gimple_statement_wce *> (gs);
> +       op (&(stmt->cleanup), cookie);
> +      }
> +      break;
> +    case GSS_ASM:
> +      {
> +       gimple_statement_asm *stmt
> +         = static_cast <gimple_statement_asm *> (gs);
> +       size_t num = (size_t)(stmt->num_ops);
> +       op (&(stmt->string), cookie);
> +       for (size_t i = 0; i != num; i++)
> +         op (&(stmt->op[i]), cookie);
> +      }
> +      break;
> +    case GSS_OMP_CRITICAL:
> +      {
> +       gimple_statement_omp_critical *stmt
> +         = static_cast <gimple_statement_omp_critical *> (gs);
> +       op (&(stmt->body), cookie);
> +       op (&(stmt->name), cookie);
> +      }
> +      break;
> +    case GSS_OMP_FOR:
> +      {
> +       gimple_statement_omp_for *stmt
> +         = static_cast <gimple_statement_omp_for *> (gs);
> +       size_t num = (size_t)(stmt->collapse);
> +       op (&(stmt->body), cookie);
> +       op (&(stmt->clauses), cookie);
> +       if (stmt->iter != NULL) {
> +         for (size_t i = 0; i != num; i++) {
> +           op (&(stmt->iter[i].index), cookie);
> +           op (&(stmt->iter[i].initial), cookie);
> +           op (&(stmt->iter[i].final), cookie);
> +           op (&(stmt->iter[i].incr), cookie);
> +         }
> +         op (&(stmt->iter), cookie);
> +       }
> +       op (&(stmt->pre_body), cookie);
> +      }
> +      break;
> +    case GSS_OMP_PARALLEL:
> +      {
> +       gimple_statement_omp_parallel *stmt
> +         = static_cast <gimple_statement_omp_parallel *> (gs);
> +       op (&(stmt->body), cookie);
> +       op (&(stmt->clauses), cookie);
> +       op (&(stmt->child_fn), cookie);
> +       op (&(stmt->data_arg), cookie);
> +      }
> +      break;
> +    case GSS_OMP_TASK:
> +      {
> +       gimple_statement_omp_task *stmt
> +         = static_cast <gimple_statement_omp_task *> (gs);
> +       op (&(stmt->body), cookie);
> +       op (&(stmt->clauses), cookie);
> +       op (&(stmt->child_fn), cookie);
> +       op (&(stmt->data_arg), cookie);
> +       op (&(stmt->copy_fn), cookie);
> +       op (&(stmt->arg_size), cookie);
> +       op (&(stmt->arg_align), cookie);
> +      }
> +      break;
> +    case GSS_OMP_SECTIONS:
> +      {
> +       gimple_statement_omp_sections *stmt
> +         = static_cast <gimple_statement_omp_sections *> (gs);
> +       op (&(stmt->body), cookie);
> +       op (&(stmt->clauses), cookie);
> +       op (&(stmt->control), cookie);
> +      }
> +      break;
> +    case GSS_OMP_SINGLE:
> +      {
> +       gimple_statement_omp_single *stmt
> +         = static_cast <gimple_statement_omp_single *> (gs);
> +       op (&(stmt->body), cookie);
> +       op (&(stmt->clauses), cookie);
> +      }
> +      break;
> +    case GSS_OMP_CONTINUE:
> +      {
> +       gimple_statement_omp_continue *stmt
> +         = static_cast <gimple_statement_omp_continue *> (gs);
> +       op (&(stmt->control_def), cookie);
> +       op (&(stmt->control_use), cookie);
> +      }
> +      break;
> +    case GSS_OMP_ATOMIC_LOAD:
> +      {
> +       gimple_statement_omp_atomic_load *stmt
> +         = static_cast <gimple_statement_omp_atomic_load *> (gs);
> +       op (&(stmt->rhs), cookie);
> +       op (&(stmt->lhs), cookie);
> +      }
> +      break;
> +    case GSS_OMP_ATOMIC_STORE:
> +      {
> +       gimple_statement_omp_atomic_store *stmt
> +         = static_cast <gimple_statement_omp_atomic_store *> (gs);
> +       op (&(stmt->val), cookie);
> +      }
> +      break;
> +    case GSS_TRANSACTION:
> +      {
> +       gimple_statement_transaction *stmt
> +         = static_cast <gimple_statement_transaction *> (gs);
> +       op (&(stmt->body), cookie);
> +       op (&(stmt->label), cookie);
> +      }
> +      break;
> +    default:
> +      break;
> +    }
> +}
> +
> +
>  #include "gt-gimple.h"
> diff --git a/gcc/gimple.h b/gcc/gimple.h
> index daab54e..9b428eb 100644
> --- a/gcc/gimple.h
> +++ b/gcc/gimple.h
> @@ -222,6 +222,12 @@ struct GTY((user)) gimple_statement_base {
>    gimple GTY((skip)) prev;
>  };
>
> +/* GTY((user)) hooks for gimple, called once per-traversal.  */
> +void gt_ggc_mx (gimple gs);
> +void gt_pch_nx (gimple gs);
> +void gt_pch_nx (gimple gs, gt_pointer_operator op, void *cookie);
> +
> +
>
>  /* Base structure for tuples with operands.  */
>
> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
> index af8685c..185c072 100644
> --- a/gcc/tree-cfg.c
> +++ b/gcc/tree-cfg.c
> @@ -8291,7 +8291,6 @@ make_pass_warn_unused_result (gcc::context *ctxt)
>  /* Garbage collection support for edge_def.  */
>
>  extern void gt_ggc_mx (tree&);
> -extern void gt_ggc_mx (gimple&);
>  extern void gt_ggc_mx (rtx&);
>  extern void gt_ggc_mx (basic_block&);
>
> @@ -8302,7 +8301,7 @@ gt_ggc_mx (edge_def *e)
>    gt_ggc_mx (e->src);
>    gt_ggc_mx (e->dest);
>    if (current_ir_type () == IR_GIMPLE)
> -    gt_ggc_mx (e->insns.g);
> +    gt_ggc_mx_gimple_statement_base (e->insns.g);
>    else
>      gt_ggc_mx (e->insns.r);
>    gt_ggc_mx (block);
> @@ -8311,7 +8310,6 @@ gt_ggc_mx (edge_def *e)
>  /* PCH support for edge_def.  */
>
>  extern void gt_pch_nx (tree&);
> -extern void gt_pch_nx (gimple&);
>  extern void gt_pch_nx (rtx&);
>  extern void gt_pch_nx (basic_block&);
>
> @@ -8322,7 +8320,7 @@ gt_pch_nx (edge_def *e)
>    gt_pch_nx (e->src);
>    gt_pch_nx (e->dest);
>    if (current_ir_type () == IR_GIMPLE)
> -    gt_pch_nx (e->insns.g);
> +    gt_pch_nx_gimple_statement_base (e->insns.g);
>    else
>      gt_pch_nx (e->insns.r);
>    gt_pch_nx (block);
> --
> 1.7.11.7
>
David Malcolm - Aug. 30, 2013, 8:12 p.m.
On Fri, 2013-08-30 at 10:40 +0200, Richard Biener wrote:
> On Thu, Aug 29, 2013 at 6:20 PM, David Malcolm <dmalcolm@redhat.com> wrote:
> >         * gimple.c (gt_ggc_mx (gimple)): New, as required by GTY((user)).
> >         (gt_pch_nx (gimple)): Likewise.
> >         (gt_pch_nx (gimple, gt_pointer_operator, void *)): Likewise.
> >         * gimple.h  (gt_ggc_mx (gimple)): Declare.
> >         (gt_pch_nx (gimple)): Declare.
> >         (gt_pch_nx (gimple, gt_pointer_operator, void *)): Declare.
> >         * tree-cfg.c (ggc_mx (gimple&)): Remove declaration, as this
> >         collides with the function that GTY((user)) expects.
> >         (gt_ggc_mx (edge_def *)): Replace call to gt_ggc_mx on the
> >         gimple with gt_ggc_mx_gimple_statement_base: in the
> >         pre-GTY((user)) world, "gt_ggc_mx" was the function to be called
> >         on a possibly NULL pointed to check if needed marking and if so
> >         to traverse its fields.  In the GTY((user)) world, "gt_ggc_mx"
> >         is the function to be called on non-NULL objects immediately *after*
> >         they have been marked: it does not mark the object itself.
> >         (gt_pch_nx (gimple&)): Remove declaration.
> >         (gt_pch_nx (edge_def *)): Update as per the mx hook.
> 
> Btw, this shows that gimple isn't a true C++ hierarchy - because of GTY
> you can only ever use 'gimple' pointers, not more specialized ones
> like gimple_phi as you are missing the GTY machinery for them.

One can definitely use pointers to subclasses on the *stack*, indeed,
the patches use this throughout; IMHO it's an improvement.

FWIW I did a quick test and was also able to add dummy bss subclass ptrs
e.g.:

  static GTY(()) gimple_statement_phi *dummy_phi;

This leads to gengtype creating code like this in gtype-desc.c:

void
gt_ggc_mx_gimple_statement_phi (void *x_p)
{
  gimple_statement_phi * const x = (gimple_statement_phi *)x_p;
  if (ggc_test_and_set_mark (x))
    {
      gt_ggc_mx (x);
    }
}

Note how the "gt_ggc_mx (x);" is resolved by using the base-class
implementation of gt_ggc_mx i.e.: gt_ggc_mx (gimple )
since a gimple_statement_phi * is-a gimple_statement_base *.

Anything more complicated than that (e.g. containers) and we're hitting
up against the limitations of gengtype, I guess.

> I'm not 100% convinced that we should do all this at this point without
> getting a better hand on the gengtype issues (it's partial transition to
> the C++ world of GCC)

[...]
David Malcolm - Aug. 31, 2013, 2:25 p.m.
On Fri, 2013-08-30 at 10:09 +0200, Richard Biener wrote:
> On Thu, Aug 29, 2013 at 9:44 PM, Steven Bosscher <stevenb.gcc@gmail.com> wrote:
> > On Thu, Aug 29, 2013 at 6:20 PM, David Malcolm <dmalcolm@redhat.com> wrote:
> >>         * gimple.c (gt_ggc_mx (gimple)): New, as required by GTY((user)).
> >>         (gt_pch_nx (gimple)): Likewise.
> >
> > GIMPLE isn't supposed to end up in a PCH. Can you please make this
> > function simply call gcc_unreachable()?
> >
> > FWIW 1: I really think all these hand-written markers aren't a good
> > idea, we should really figure out a way to have automatic marker
> > function generators, something less complex than gengtype, of course.
> > But to have all these calls to the type-mangled marker functions
> > (gt_pch_n_9tree_node, etc.) is going to be a problem in the long term.
> >
> > It seems to me that the first step in all these conversions to
> > hand-written markers should be to make gengtype spit out the marker
> > functions *without* the type name mangling, i.e. all marker functions
> > should just be gt_ggc_mx(type) / gt_pch_nx(type).
> 
> Yes, the original idea was that gengtype would do that.  For things we like
> to optimize the GTY((user)) thing would tell it that we do provide the markers.
> Like when you want to look through a non-GCed intermediate object.  Or
> for things like GTY((chain)) stuff that doesn't really work if you have multiple
> chains (without clever GTY((skip))s...).
> 
> The lack of the unmangled overloads is annoying :/  IIRC Diego halfway completed
> the transition to unmangled overloads / specializations?

How would that work, and is that something that it would be productive
for me to work on?

Currently AIUI gtype-desc.h contains mangled macros and decls e.g.:
  extern void gt_ggc_mx_rtvec_def (void *);
  #define gt_ggc_m_9rtvec_def(X) do { \
    if (X != NULL) gt_ggc_mx_rtvec_def (X);\
    } while (0)

and the corresponding functions in gtype-desc.c contain:

void
gt_ggc_mx_rtvec_def (void *x_p)
{
  struct rtvec_def * const x = (struct rtvec_def *)x_p;
  if (ggc_test_and_set_mark (x))
    {
	/* visit fields of x, invoking the macros */
    }
}

Is the goal for the field-visiting code to all be able to simply do:
   gt_ggc_mx (field)
and have overloading resolve it all? (and handle e.g. chain_next etc
etc)

Presumably if this were implemented, then hand-written GTY functions
would be that much easier to maintain, and perhaps this gimple
conversion idea would be more acceptable?  (or, in other words, should I
work on this?)

Thanks
Dave
Richard Guenther - Aug. 31, 2013, 5:27 p.m.
David Malcolm <dmalcolm@redhat.com> wrote:
>On Fri, 2013-08-30 at 10:09 +0200, Richard Biener wrote:
>> On Thu, Aug 29, 2013 at 9:44 PM, Steven Bosscher
><stevenb.gcc@gmail.com> wrote:
>> > On Thu, Aug 29, 2013 at 6:20 PM, David Malcolm
><dmalcolm@redhat.com> wrote:
>> >>         * gimple.c (gt_ggc_mx (gimple)): New, as required by
>GTY((user)).
>> >>         (gt_pch_nx (gimple)): Likewise.
>> >
>> > GIMPLE isn't supposed to end up in a PCH. Can you please make this
>> > function simply call gcc_unreachable()?
>> >
>> > FWIW 1: I really think all these hand-written markers aren't a good
>> > idea, we should really figure out a way to have automatic marker
>> > function generators, something less complex than gengtype, of
>course.
>> > But to have all these calls to the type-mangled marker functions
>> > (gt_pch_n_9tree_node, etc.) is going to be a problem in the long
>term.
>> >
>> > It seems to me that the first step in all these conversions to
>> > hand-written markers should be to make gengtype spit out the marker
>> > functions *without* the type name mangling, i.e. all marker
>functions
>> > should just be gt_ggc_mx(type) / gt_pch_nx(type).
>> 
>> Yes, the original idea was that gengtype would do that.  For things
>we like
>> to optimize the GTY((user)) thing would tell it that we do provide
>the markers.
>> Like when you want to look through a non-GCed intermediate object. 
>Or
>> for things like GTY((chain)) stuff that doesn't really work if you
>have multiple
>> chains (without clever GTY((skip))s...).
>> 
>> The lack of the unmangled overloads is annoying :/  IIRC Diego
>halfway completed
>> the transition to unmangled overloads / specializations?
>
>How would that work, and is that something that it would be productive
>for me to work on?
>
>Currently AIUI gtype-desc.h contains mangled macros and decls e.g.:
>  extern void gt_ggc_mx_rtvec_def (void *);
>  #define gt_ggc_m_9rtvec_def(X) do { \
>    if (X != NULL) gt_ggc_mx_rtvec_def (X);\
>    } while (0)
>
>and the corresponding functions in gtype-desc.c contain:
>
>void
>gt_ggc_mx_rtvec_def (void *x_p)
>{
>  struct rtvec_def * const x = (struct rtvec_def *)x_p;
>  if (ggc_test_and_set_mark (x))
>    {
>	/* visit fields of x, invoking the macros */
>    }
>}
>
>Is the goal for the field-visiting code to all be able to simply do:
>   gt_ggc_mx (field)

Yes. The advantage is that gengtype this way only needs to parse field names and not types which is a lot easier.

>and have overloading resolve it all? (and handle e.g. chain_next etc
>etc)

Yes. All bits that would require more complex parsing should instead be telled explicit via a GTY annotation.

>Presumably if this were implemented, then hand-written GTY functions
>would be that much easier to maintain, and perhaps this gimple
>conversion idea would be more acceptable?  (or, in other words, should
>I
>work on this?)

That would be very nice! IIRC Diego had issues with making all declarations visible to make this work. Diego?

Richard.

>Thanks
>Dave
David Malcolm - Sept. 4, 2013, 3:40 p.m.
On Sat, 2013-08-31 at 19:27 +0200, Richard Biener wrote:
> David Malcolm <dmalcolm@redhat.com> wrote:
> >On Fri, 2013-08-30 at 10:09 +0200, Richard Biener wrote:
> >> On Thu, Aug 29, 2013 at 9:44 PM, Steven Bosscher
> ><stevenb.gcc@gmail.com> wrote:
> >> > On Thu, Aug 29, 2013 at 6:20 PM, David Malcolm
> ><dmalcolm@redhat.com> wrote:
> >> >>         * gimple.c (gt_ggc_mx (gimple)): New, as required by
> >GTY((user)).
> >> >>         (gt_pch_nx (gimple)): Likewise.
> >> >
> >> > GIMPLE isn't supposed to end up in a PCH. Can you please make this
> >> > function simply call gcc_unreachable()?
> >> >
> >> > FWIW 1: I really think all these hand-written markers aren't a good
> >> > idea, we should really figure out a way to have automatic marker
> >> > function generators, something less complex than gengtype, of
> >course.
> >> > But to have all these calls to the type-mangled marker functions
> >> > (gt_pch_n_9tree_node, etc.) is going to be a problem in the long
> >term.
> >> >
> >> > It seems to me that the first step in all these conversions to
> >> > hand-written markers should be to make gengtype spit out the marker
> >> > functions *without* the type name mangling, i.e. all marker
> >functions
> >> > should just be gt_ggc_mx(type) / gt_pch_nx(type).
> >> 
> >> Yes, the original idea was that gengtype would do that.  For things
> >we like
> >> to optimize the GTY((user)) thing would tell it that we do provide
> >the markers.
> >> Like when you want to look through a non-GCed intermediate object. 
> >Or
> >> for things like GTY((chain)) stuff that doesn't really work if you
> >have multiple
> >> chains (without clever GTY((skip))s...).
> >> 
> >> The lack of the unmangled overloads is annoying :/  IIRC Diego
> >halfway completed
> >> the transition to unmangled overloads / specializations?
> >
> >How would that work, and is that something that it would be productive
> >for me to work on?
> >
> >Currently AIUI gtype-desc.h contains mangled macros and decls e.g.:
> >  extern void gt_ggc_mx_rtvec_def (void *);
> >  #define gt_ggc_m_9rtvec_def(X) do { \
> >    if (X != NULL) gt_ggc_mx_rtvec_def (X);\
> >    } while (0)
> >
> >and the corresponding functions in gtype-desc.c contain:
> >
> >void
> >gt_ggc_mx_rtvec_def (void *x_p)
> >{
> >  struct rtvec_def * const x = (struct rtvec_def *)x_p;
> >  if (ggc_test_and_set_mark (x))
> >    {
> >	/* visit fields of x, invoking the macros */
> >    }
> >}
> >
> >Is the goal for the field-visiting code to all be able to simply do:
> >   gt_ggc_mx (field)
> 
> Yes. The advantage is that gengtype this way only needs to parse field names and not types which is a lot easier.
> 
> >and have overloading resolve it all? (and handle e.g. chain_next etc
> >etc)
> 
> Yes. All bits that would require more complex parsing should instead be telled explicit via a GTY annotation.
> 
> >Presumably if this were implemented, then hand-written GTY functions
> >would be that much easier to maintain, and perhaps this gimple
> >conversion idea would be more acceptable?  (or, in other words, should
> >I
> >work on this?)
> 
> That would be very nice! IIRC Diego had issues with making all declarations visible to make this work. Diego?

An update: I've been trying this, but I'm running into what may be a
blocker: types need to be visible in the declaration of the marker
function.  Doing this in gtype-desc.h runs into a tangle of dependency
issues.  For example:

  ./gtype-desc.h:2842:28: error: ‘ivarref_entry’ was not declared in this scope
  extern void gt_ggc_mx (vec<ivarref_entry,va_gc> *p);
                      ^
In the extreme case, the underlying types in question might be only
declared in one specific .c file.  In other cases, there's likely to be
some set of header files needed to get at the types.  Also, vec.h uses
ggc.h, which uses gtype-desc.h, and so we have a loop...

AIUI, the mangled names of types in the function names are doing the job
of hiding all the types in gtype-desc.h, so that they are only needed in
the various gt-*.h files and in gtype-desc.c.  By changing things so
that the marker function declarations refer to the types directly, all
types need to be known to users of such functions.  I'm not sure that
that's possible - or, at least, not if the declarations are in a shared
header file.

Perhaps it could work with some scheme in which the types are
partitioned by .h/.c file, and copies of forward declarations are added
only as-needed to the appropriate gt-*.h/gtype-desc.c files?

I'm trying this now.

BTW, what is the etymology of "gt_ggc_mx" and "gt_pch_nx", and how do
people pronounce them? (I call them the "object-marking" and
"object-noting" hooks" fwiw).  As far as I can see, the "m" and and the
"n" come from "mark" and "note"; it's not clear to me where the trailing
"x" came from.

Dave
Richard Guenther - Sept. 5, 2013, 9:08 a.m.
On Wed, Sep 4, 2013 at 5:40 PM, David Malcolm <dmalcolm@redhat.com> wrote:
> On Sat, 2013-08-31 at 19:27 +0200, Richard Biener wrote:
>> David Malcolm <dmalcolm@redhat.com> wrote:
>> >On Fri, 2013-08-30 at 10:09 +0200, Richard Biener wrote:
>> >> On Thu, Aug 29, 2013 at 9:44 PM, Steven Bosscher
>> ><stevenb.gcc@gmail.com> wrote:
>> >> > On Thu, Aug 29, 2013 at 6:20 PM, David Malcolm
>> ><dmalcolm@redhat.com> wrote:
>> >> >>         * gimple.c (gt_ggc_mx (gimple)): New, as required by
>> >GTY((user)).
>> >> >>         (gt_pch_nx (gimple)): Likewise.
>> >> >
>> >> > GIMPLE isn't supposed to end up in a PCH. Can you please make this
>> >> > function simply call gcc_unreachable()?
>> >> >
>> >> > FWIW 1: I really think all these hand-written markers aren't a good
>> >> > idea, we should really figure out a way to have automatic marker
>> >> > function generators, something less complex than gengtype, of
>> >course.
>> >> > But to have all these calls to the type-mangled marker functions
>> >> > (gt_pch_n_9tree_node, etc.) is going to be a problem in the long
>> >term.
>> >> >
>> >> > It seems to me that the first step in all these conversions to
>> >> > hand-written markers should be to make gengtype spit out the marker
>> >> > functions *without* the type name mangling, i.e. all marker
>> >functions
>> >> > should just be gt_ggc_mx(type) / gt_pch_nx(type).
>> >>
>> >> Yes, the original idea was that gengtype would do that.  For things
>> >we like
>> >> to optimize the GTY((user)) thing would tell it that we do provide
>> >the markers.
>> >> Like when you want to look through a non-GCed intermediate object.
>> >Or
>> >> for things like GTY((chain)) stuff that doesn't really work if you
>> >have multiple
>> >> chains (without clever GTY((skip))s...).
>> >>
>> >> The lack of the unmangled overloads is annoying :/  IIRC Diego
>> >halfway completed
>> >> the transition to unmangled overloads / specializations?
>> >
>> >How would that work, and is that something that it would be productive
>> >for me to work on?
>> >
>> >Currently AIUI gtype-desc.h contains mangled macros and decls e.g.:
>> >  extern void gt_ggc_mx_rtvec_def (void *);
>> >  #define gt_ggc_m_9rtvec_def(X) do { \
>> >    if (X != NULL) gt_ggc_mx_rtvec_def (X);\
>> >    } while (0)
>> >
>> >and the corresponding functions in gtype-desc.c contain:
>> >
>> >void
>> >gt_ggc_mx_rtvec_def (void *x_p)
>> >{
>> >  struct rtvec_def * const x = (struct rtvec_def *)x_p;
>> >  if (ggc_test_and_set_mark (x))
>> >    {
>> >     /* visit fields of x, invoking the macros */
>> >    }
>> >}
>> >
>> >Is the goal for the field-visiting code to all be able to simply do:
>> >   gt_ggc_mx (field)
>>
>> Yes. The advantage is that gengtype this way only needs to parse field names and not types which is a lot easier.
>>
>> >and have overloading resolve it all? (and handle e.g. chain_next etc
>> >etc)
>>
>> Yes. All bits that would require more complex parsing should instead be telled explicit via a GTY annotation.
>>
>> >Presumably if this were implemented, then hand-written GTY functions
>> >would be that much easier to maintain, and perhaps this gimple
>> >conversion idea would be more acceptable?  (or, in other words, should
>> >I
>> >work on this?)
>>
>> That would be very nice! IIRC Diego had issues with making all declarations visible to make this work. Diego?
>
> An update: I've been trying this, but I'm running into what may be a
> blocker: types need to be visible in the declaration of the marker
> function.  Doing this in gtype-desc.h runs into a tangle of dependency
> issues.  For example:
>
>   ./gtype-desc.h:2842:28: error: ‘ivarref_entry’ was not declared in this scope
>   extern void gt_ggc_mx (vec<ivarref_entry,va_gc> *p);
>                       ^
> In the extreme case, the underlying types in question might be only
> declared in one specific .c file.  In other cases, there's likely to be
> some set of header files needed to get at the types.  Also, vec.h uses
> ggc.h, which uses gtype-desc.h, and so we have a loop...
>
> AIUI, the mangled names of types in the function names are doing the job
> of hiding all the types in gtype-desc.h, so that they are only needed in
> the various gt-*.h files and in gtype-desc.c.  By changing things so
> that the marker function declarations refer to the types directly, all
> types need to be known to users of such functions.  I'm not sure that
> that's possible - or, at least, not if the declarations are in a shared
> header file.

I think that's the issue Diego ran into.  The theory with the idea was
that at the point of the struct declaration we want to generate the
marker for all those types are properly declared so their marking
prototypes would work.  Which means that the marker declarations
should go alongside with struct definitions.

One idea would be to simply require explicit declarations of them
after their structs declaration.

> Perhaps it could work with some scheme in which the types are
> partitioned by .h/.c file, and copies of forward declarations are added
> only as-needed to the appropriate gt-*.h/gtype-desc.c files?

Not sure if forward declarations would work - at least autogenerated ones.
That would require gengtype parsing field types again.

Richard.

> I'm trying this now.
>
> BTW, what is the etymology of "gt_ggc_mx" and "gt_pch_nx", and how do
> people pronounce them? (I call them the "object-marking" and
> "object-noting" hooks" fwiw).  As far as I can see, the "m" and and the
> "n" come from "mark" and "note"; it's not clear to me where the trailing
> "x" came from.
>
> Dave
>
Diego Novillo - Sept. 5, 2013, 10:49 a.m.
On Wed, Sep 4, 2013 at 11:40 AM, David Malcolm <dmalcolm@redhat.com> wrote:
> On Sat, 2013-08-31 at 19:27 +0200, Richard Biener wrote:
>> David Malcolm <dmalcolm@redhat.com> wrote:
>> >On Fri, 2013-08-30 at 10:09 +0200, Richard Biener wrote:
>> >> On Thu, Aug 29, 2013 at 9:44 PM, Steven Bosscher
>> ><stevenb.gcc@gmail.com> wrote:
>> >> > On Thu, Aug 29, 2013 at 6:20 PM, David Malcolm
>> ><dmalcolm@redhat.com> wrote:
>> >> >>         * gimple.c (gt_ggc_mx (gimple)): New, as required by
>> >GTY((user)).
>> >> >>         (gt_pch_nx (gimple)): Likewise.
>> >> >
>> >> > GIMPLE isn't supposed to end up in a PCH. Can you please make this
>> >> > function simply call gcc_unreachable()?
>> >> >
>> >> > FWIW 1: I really think all these hand-written markers aren't a good
>> >> > idea, we should really figure out a way to have automatic marker
>> >> > function generators, something less complex than gengtype, of
>> >course.
>> >> > But to have all these calls to the type-mangled marker functions
>> >> > (gt_pch_n_9tree_node, etc.) is going to be a problem in the long
>> >term.
>> >> >
>> >> > It seems to me that the first step in all these conversions to
>> >> > hand-written markers should be to make gengtype spit out the marker
>> >> > functions *without* the type name mangling, i.e. all marker
>> >functions
>> >> > should just be gt_ggc_mx(type) / gt_pch_nx(type).
>> >>
>> >> Yes, the original idea was that gengtype would do that.  For things
>> >we like
>> >> to optimize the GTY((user)) thing would tell it that we do provide
>> >the markers.
>> >> Like when you want to look through a non-GCed intermediate object.
>> >Or
>> >> for things like GTY((chain)) stuff that doesn't really work if you
>> >have multiple
>> >> chains (without clever GTY((skip))s...).
>> >>
>> >> The lack of the unmangled overloads is annoying :/  IIRC Diego
>> >halfway completed
>> >> the transition to unmangled overloads / specializations?
>> >
>> >How would that work, and is that something that it would be productive
>> >for me to work on?
>> >
>> >Currently AIUI gtype-desc.h contains mangled macros and decls e.g.:
>> >  extern void gt_ggc_mx_rtvec_def (void *);
>> >  #define gt_ggc_m_9rtvec_def(X) do { \
>> >    if (X != NULL) gt_ggc_mx_rtvec_def (X);\
>> >    } while (0)
>> >
>> >and the corresponding functions in gtype-desc.c contain:
>> >
>> >void
>> >gt_ggc_mx_rtvec_def (void *x_p)
>> >{
>> >  struct rtvec_def * const x = (struct rtvec_def *)x_p;
>> >  if (ggc_test_and_set_mark (x))
>> >    {
>> >     /* visit fields of x, invoking the macros */
>> >    }
>> >}
>> >
>> >Is the goal for the field-visiting code to all be able to simply do:
>> >   gt_ggc_mx (field)
>>
>> Yes. The advantage is that gengtype this way only needs to parse field names and not types which is a lot easier.
>>
>> >and have overloading resolve it all? (and handle e.g. chain_next etc
>> >etc)
>>
>> Yes. All bits that would require more complex parsing should instead be telled explicit via a GTY annotation.
>>
>> >Presumably if this were implemented, then hand-written GTY functions
>> >would be that much easier to maintain, and perhaps this gimple
>> >conversion idea would be more acceptable?  (or, in other words, should
>> >I
>> >work on this?)
>>
>> That would be very nice! IIRC Diego had issues with making all declarations visible to make this work. Diego?

Yes.  I ran into the same problem that David just described.  When
trying to unmangle all the markers, you now require gengtype to have
actual visibility into all the headers, so that the compiler can see
the actual type definitions to resolve the overloads.

> An update: I've been trying this, but I'm running into what may be a
> blocker: types need to be visible in the declaration of the marker
> function.  Doing this in gtype-desc.h runs into a tangle of dependency
> issues.  For example:
>
>   ./gtype-desc.h:2842:28: error: ‘ivarref_entry’ was not declared in this scope
>   extern void gt_ggc_mx (vec<ivarref_entry,va_gc> *p);

This kind of issue.  Yes.

Perhaps this could be solved by not having a single header generated
for the markers.  Instead, markers are generated in separate header
files that are #included by the headers that have the actual type
definitions needed for the overloads to work.  Ditto for gtype-desc.c.

> BTW, what is the etymology of "gt_ggc_mx" and "gt_pch_nx", and how do
> people pronounce them? (I call them the "object-marking" and
> "object-noting" hooks" fwiw).  As far as I can see, the "m" and and the
> "n" come from "mark" and "note"; it's not clear to me where the trailing
> "x" came from.

That's how I think of them too.  I'm not sure what the 'x' denotes.


Diego.

Patch

diff --git a/gcc/gimple.c b/gcc/gimple.c
index 1ad36d1..dd99cda 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -4338,4 +4338,747 @@  build_type_cast (tree to_type, gimple op, enum ssa_mode mode)
   return build_type_cast (to_type, gimple_assign_lhs (op), mode);
 }
 
+void
+gt_ggc_mx (gimple gs)
+{
+  gimple x = gs;
+  /* Emulation of the "chain_next" GTY attribute.
+
+     gs has already been marked.
+     Iterate the chain of next statements, marking until we reach one that
+     has already been marked, or NULL.   */
+  gimple xlimit = gs->next;
+  while (ggc_test_and_set_mark (xlimit))
+    xlimit = xlimit->next;
+
+  /* All of the statements within the half-open interval [x..xlimit) have
+     just been marked.  Iterate through the list, visiting their fields.  */
+  while (x != xlimit)
+    {
+      gt_ggc_m_15basic_block_def (x->bb);
+      switch (gimple_statement_structure (&((*x))))
+	{
+	case GSS_BASE:
+	  break;
+	case GSS_WITH_OPS:
+	  {
+	    gimple_statement_with_ops *stmt
+	      = static_cast <gimple_statement_with_ops *> (x);
+	    size_t num = (size_t)(stmt->num_ops);
+	    for (size_t i = 0; i != num; i++)
+	      gt_ggc_m_9tree_node (stmt->op[i]);
+	  }
+	  break;
+	case GSS_WITH_MEM_OPS_BASE:
+	  break;
+	case GSS_WITH_MEM_OPS:
+	  {
+	    gimple_statement_with_memory_ops *stmt
+	      = static_cast <gimple_statement_with_memory_ops *> (x);
+	    size_t num = (size_t)(stmt->num_ops);
+	    for (size_t i = 0; i != num; i++)
+	      gt_ggc_m_9tree_node (stmt->op[i]);
+	  }
+	  break;
+	case GSS_CALL:
+	  {
+	    gimple_statement_call *stmt
+	      = static_cast <gimple_statement_call *> (x);
+	    gt_ggc_m_15bitmap_head_def (stmt->call_used.vars);
+	    gt_ggc_m_15bitmap_head_def (stmt->call_clobbered.vars);
+	    switch (stmt->subcode & GF_CALL_INTERNAL)
+	      {
+	      case 0:
+		gt_ggc_m_9tree_node (stmt->u.fntype);
+		break;
+	      case GF_CALL_INTERNAL:
+		break;
+	      default:
+		break;
+	      }
+	    size_t num = (size_t)(stmt->num_ops);
+	    for (size_t i = 0; i != num; i++)
+	      gt_ggc_m_9tree_node (stmt->op[i]);
+	  }
+	  break;
+	case GSS_OMP:
+	  {
+	    gimple_statement_omp *stmt
+	      = static_cast <gimple_statement_omp *> (x);
+	    gt_ggc_mx_gimple_statement_base (stmt->body);
+	  }
+	  break;
+	case GSS_BIND:
+	  {
+	     gimple_statement_bind *stmt
+	      = static_cast <gimple_statement_bind *> (x);
+	    gt_ggc_m_9tree_node (stmt->vars);
+	    gt_ggc_m_9tree_node (stmt->block);
+	    gt_ggc_mx_gimple_statement_base (stmt->body);
+	  }
+	  break;
+	case GSS_CATCH:
+	  {
+	    gimple_statement_catch *stmt
+	      = static_cast <gimple_statement_catch *> (x);
+	    gt_ggc_m_9tree_node (stmt->types);
+	    gt_ggc_mx_gimple_statement_base (stmt->handler);
+	  }
+	  break;
+	case GSS_EH_FILTER:
+	  {
+	    gimple_statement_eh_filter *stmt
+	      = static_cast <gimple_statement_eh_filter *> (x);
+	    gt_ggc_m_9tree_node (stmt->types);
+	    gt_ggc_mx_gimple_statement_base (stmt->failure);
+	  }
+	  break;
+	case GSS_EH_MNT:
+	  {
+	    gimple_statement_eh_mnt *stmt
+	      = static_cast <gimple_statement_eh_mnt *> (x);
+	    gt_ggc_m_9tree_node (stmt->fndecl);
+	  }
+	  break;
+	case GSS_EH_ELSE:
+	  {
+	    gimple_statement_eh_else*stmt
+	      = static_cast <gimple_statement_eh_else *> (x);
+	    gt_ggc_mx_gimple_statement_base (stmt->n_body);
+	    gt_ggc_mx_gimple_statement_base (stmt->e_body);
+	  }
+	  break;
+	case GSS_PHI:
+	  {
+	    gimple_statement_phi *stmt
+	      = static_cast <gimple_statement_phi *> (x);
+	    size_t num = (size_t)(stmt->nargs);
+	    gt_ggc_m_9tree_node (stmt->result);
+	    for (size_t i = 0; i != num; i++)
+	      gt_ggc_m_9tree_node (stmt->args[i].def);
+	  }
+	  break;
+	case GSS_EH_CTRL:
+	  break;
+	case GSS_TRY:
+	  {
+	    gimple_statement_try *stmt
+	      = static_cast <gimple_statement_try *> (x);
+	    gt_ggc_mx_gimple_statement_base (stmt->eval);
+	    gt_ggc_mx_gimple_statement_base (stmt->cleanup);
+	  }
+	  break;
+	case GSS_WCE:
+	  {
+	    gimple_statement_wce *stmt
+	      = static_cast <gimple_statement_wce *> (x);
+	    gt_ggc_mx_gimple_statement_base (stmt->cleanup);
+	  }
+	  break;
+	case GSS_ASM:
+	  {
+	    gimple_statement_asm *stmt
+	      = static_cast <gimple_statement_asm *> (x);
+	    size_t num = (size_t)(stmt->num_ops);
+	    gt_ggc_m_S (stmt->string);
+	    for (size_t i = 0; i != num; i++)
+	      gt_ggc_m_9tree_node (stmt->op[i]);
+	  }
+	  break;
+	case GSS_OMP_CRITICAL:
+	  {
+	    gimple_statement_omp_critical *stmt
+	      = static_cast <gimple_statement_omp_critical *> (x);
+	    gt_ggc_mx_gimple_statement_base (stmt->body);
+	    gt_ggc_m_9tree_node (stmt->name);
+	  }
+	  break;
+	case GSS_OMP_FOR:
+	  {
+	    gimple_statement_omp_for *stmt
+	      = static_cast <gimple_statement_omp_for *> (x);
+	    size_t num = (size_t)(stmt->collapse);
+	    gt_ggc_mx_gimple_statement_base (stmt->body);
+	    gt_ggc_m_9tree_node (stmt->clauses);
+	    if (stmt->iter != NULL) {
+	      for (size_t i = 0; i != num; i++) {
+		gt_ggc_m_9tree_node (stmt->iter[i].index);
+		gt_ggc_m_9tree_node (stmt->iter[i].initial);
+		gt_ggc_m_9tree_node (stmt->iter[i].final);
+		gt_ggc_m_9tree_node (stmt->iter[i].incr);
+	      }
+	      ggc_mark (stmt->iter);
+	    }
+	    gt_ggc_mx_gimple_statement_base (stmt->pre_body);
+	  }
+	  break;
+	case GSS_OMP_PARALLEL:
+	  {
+	    gimple_statement_omp_parallel *stmt
+	      = static_cast <gimple_statement_omp_parallel *> (x);
+	    gt_ggc_mx_gimple_statement_base (stmt->body);
+	    gt_ggc_m_9tree_node (stmt->clauses);
+	    gt_ggc_m_9tree_node (stmt->child_fn);
+	    gt_ggc_m_9tree_node (stmt->data_arg);
+	  }
+	  break;
+	case GSS_OMP_TASK:
+	  {
+	    gimple_statement_omp_task *stmt
+	      = static_cast <gimple_statement_omp_task *> (x);
+	    gt_ggc_mx_gimple_statement_base (stmt->body);
+	    gt_ggc_m_9tree_node (stmt->clauses);
+	    gt_ggc_m_9tree_node (stmt->child_fn);
+	    gt_ggc_m_9tree_node (stmt->data_arg);
+	    gt_ggc_m_9tree_node (stmt->copy_fn);
+	    gt_ggc_m_9tree_node (stmt->arg_size);
+	    gt_ggc_m_9tree_node (stmt->arg_align);
+	  }
+	  break;
+	case GSS_OMP_SECTIONS:
+	  {
+	    gimple_statement_omp_sections *stmt
+	      = static_cast <gimple_statement_omp_sections *> (x);
+	    gt_ggc_mx_gimple_statement_base (stmt->body);
+	    gt_ggc_m_9tree_node (stmt->clauses);
+	    gt_ggc_m_9tree_node (stmt->control);
+	  }
+	  break;
+	case GSS_OMP_SINGLE:
+	  {
+	    gimple_statement_omp_single *stmt
+	      = static_cast <gimple_statement_omp_single *> (x);
+	    gt_ggc_mx_gimple_statement_base (stmt->body);
+	    gt_ggc_m_9tree_node (stmt->clauses);
+	  }
+	  break;
+	case GSS_OMP_CONTINUE:
+	  {
+	    gimple_statement_omp_continue *stmt
+	      = static_cast <gimple_statement_omp_continue *> (x);
+	    gt_ggc_m_9tree_node (stmt->control_def);
+	    gt_ggc_m_9tree_node (stmt->control_use);
+	  }
+	  break;
+	case GSS_OMP_ATOMIC_LOAD:
+	  {
+	    gimple_statement_omp_atomic_load *stmt
+	      = static_cast <gimple_statement_omp_atomic_load *> (x);
+	    gt_ggc_m_9tree_node (stmt->rhs);
+	    gt_ggc_m_9tree_node (stmt->lhs);
+	  }
+	  break;
+	case GSS_OMP_ATOMIC_STORE:
+	  {
+	    gimple_statement_omp_atomic_store *stmt
+	      = static_cast <gimple_statement_omp_atomic_store *> (x);
+	    gt_ggc_m_9tree_node (stmt->val);
+	  }
+	  break;
+	case GSS_TRANSACTION:
+	  {
+	    gimple_statement_transaction *stmt
+	      = static_cast <gimple_statement_transaction *> (x);
+	    gt_ggc_mx_gimple_statement_base (stmt->body);
+	    gt_ggc_m_9tree_node (stmt->label);
+	  }
+	  break;
+	default:
+	  break;
+	}
+      x = x->next;
+    }
+}
+
+void
+gt_pch_nx (gimple gs)
+{
+  gimple x = gs;
+  /* Emulation of the "chain_next" GTY attribute.
+
+     gs has already been marked.
+     Iterate the chain of next statements, marking until we reach one that
+     has already been marked, or NULL.   */
+  gimple xlimit = gs->next;
+  while (gt_pch_note_object (xlimit, xlimit, gt_pch_p_21gimple_statement_base))
+    xlimit = xlimit->next;
+
+  /* All of the statements within the half-open interval [x..xlimit) have
+     just been marked.  Iterate through the list, visiting their fields.  */
+  while (x != xlimit)
+    {
+      gt_pch_n_15basic_block_def (x->bb);
+      switch (gimple_statement_structure (&((*x))))
+	{
+	case GSS_BASE:
+	  break;
+	case GSS_WITH_OPS:
+	  {
+	    gimple_statement_with_ops *stmt
+	      = static_cast <gimple_statement_with_ops *> (x);
+	    size_t num = (size_t)(stmt->num_ops);
+	    for (size_t i = 0; i != num; i++)
+	      gt_pch_n_9tree_node (stmt->op[i]);
+	  }
+	  break;
+	case GSS_WITH_MEM_OPS_BASE:
+	  break;
+	case GSS_WITH_MEM_OPS:
+	  {
+	    gimple_statement_with_memory_ops *stmt
+	      = static_cast <gimple_statement_with_memory_ops *> (x);
+	    size_t num = (size_t)(stmt->num_ops);
+	    for (size_t i = 0; i != num; i++)
+	      gt_pch_n_9tree_node (stmt->op[i]);
+	  }
+	  break;
+	case GSS_CALL:
+	  {
+	    gimple_statement_call *stmt
+	      = static_cast <gimple_statement_call *> (x);
+	    gt_pch_n_15bitmap_head_def (stmt->call_used.vars);
+	    gt_pch_n_15bitmap_head_def (stmt->call_clobbered.vars);
+	    switch (stmt->subcode & GF_CALL_INTERNAL)
+	      {
+	      case 0:
+		gt_pch_n_9tree_node (stmt->u.fntype);
+		break;
+	      case GF_CALL_INTERNAL:
+		break;
+	      default:
+		break;
+	      }
+	    size_t num = (size_t)(stmt->num_ops);
+	    for (size_t i = 0; i != num; i++)
+	      gt_pch_n_9tree_node (stmt->op[i]);
+	  }
+	  break;
+	case GSS_OMP:
+	  {
+	    gimple_statement_omp *stmt
+	      = static_cast <gimple_statement_omp *> (x);
+	    gt_pch_nx_gimple_statement_base (stmt->body);
+	  }
+	  break;
+	case GSS_BIND:
+	  {
+	     gimple_statement_bind *stmt
+	      = static_cast <gimple_statement_bind *> (x);
+	    gt_pch_n_9tree_node (stmt->vars);
+	    gt_pch_n_9tree_node (stmt->block);
+	    gt_pch_nx_gimple_statement_base (stmt->body);
+	  }
+	  break;
+	case GSS_CATCH:
+	  {
+	    gimple_statement_catch *stmt
+	      = static_cast <gimple_statement_catch *> (x);
+	    gt_pch_n_9tree_node (stmt->types);
+	    gt_pch_nx_gimple_statement_base (stmt->handler);
+	  }
+	  break;
+	case GSS_EH_FILTER:
+	  {
+	    gimple_statement_eh_filter *stmt
+	      = static_cast <gimple_statement_eh_filter *> (x);
+	    gt_pch_n_9tree_node (stmt->types);
+	    gt_pch_nx_gimple_statement_base (stmt->failure);
+	  }
+	  break;
+	case GSS_EH_MNT:
+	  {
+	    gimple_statement_eh_mnt *stmt
+	      = static_cast <gimple_statement_eh_mnt *> (x);
+	    gt_pch_n_9tree_node (stmt->fndecl);
+	  }
+	  break;
+	case GSS_EH_ELSE:
+	  {
+	    gimple_statement_eh_else*stmt
+	      = static_cast <gimple_statement_eh_else *> (x);
+	    gt_pch_nx_gimple_statement_base (stmt->n_body);
+	    gt_pch_nx_gimple_statement_base (stmt->e_body);
+	  }
+	  break;
+	case GSS_PHI:
+	  {
+	    gimple_statement_phi *stmt
+	      = static_cast <gimple_statement_phi *> (x);
+	    size_t num = (size_t)(stmt->nargs);
+	    gt_pch_n_9tree_node (stmt->result);
+	    for (size_t i = 0; i != num; i++)
+	      gt_pch_n_9tree_node (stmt->args[i].def);
+	  }
+	  break;
+	case GSS_EH_CTRL:
+	  break;
+	case GSS_TRY:
+	  {
+	    gimple_statement_try *stmt
+	      = static_cast <gimple_statement_try *> (x);
+	    gt_pch_nx_gimple_statement_base (stmt->eval);
+	    gt_pch_nx_gimple_statement_base (stmt->cleanup);
+	  }
+	  break;
+	case GSS_WCE:
+	  {
+	    gimple_statement_wce *stmt
+	      = static_cast <gimple_statement_wce *> (x);
+	    gt_pch_nx_gimple_statement_base (stmt->cleanup);
+	  }
+	  break;
+	case GSS_ASM:
+	  {
+	    gimple_statement_asm *stmt
+	      = static_cast <gimple_statement_asm *> (x);
+	    size_t num = (size_t)(stmt->num_ops);
+	    gt_pch_n_S (stmt->string);
+	    for (size_t i = 0; i != num; i++)
+	      gt_pch_n_9tree_node (stmt->op[i]);
+	  }
+	  break;
+	case GSS_OMP_CRITICAL:
+	  {
+	    gimple_statement_omp_critical *stmt
+	      = static_cast <gimple_statement_omp_critical *> (x);
+	    gt_pch_nx_gimple_statement_base (stmt->body);
+	    gt_pch_n_9tree_node (stmt->name);
+	  }
+	  break;
+	case GSS_OMP_FOR:
+	  {
+	    gimple_statement_omp_for *stmt
+	      = static_cast <gimple_statement_omp_for *> (x);
+	    size_t num = (size_t)(stmt->collapse);
+	    gt_pch_nx_gimple_statement_base (stmt->body);
+	    gt_pch_n_9tree_node (stmt->clauses);
+	    if (stmt->iter != NULL) {
+	      for (size_t i = 0; i != num; i++) {
+		gt_pch_n_9tree_node (stmt->iter[i].index);
+		gt_pch_n_9tree_node (stmt->iter[i].initial);
+		gt_pch_n_9tree_node (stmt->iter[i].final);
+		gt_pch_n_9tree_node (stmt->iter[i].incr);
+	      }
+	      gt_pch_note_object (stmt->iter, x,
+				  gt_pch_p_21gimple_statement_base);
+	    }
+	    gt_pch_nx_gimple_statement_base (stmt->pre_body);
+	  }
+	  break;
+	case GSS_OMP_PARALLEL:
+	  {
+	    gimple_statement_omp_parallel *stmt
+	      = static_cast <gimple_statement_omp_parallel *> (x);
+	    gt_pch_nx_gimple_statement_base (stmt->body);
+	    gt_pch_n_9tree_node (stmt->clauses);
+	    gt_pch_n_9tree_node (stmt->child_fn);
+	    gt_pch_n_9tree_node (stmt->data_arg);
+	  }
+	  break;
+	case GSS_OMP_TASK:
+	  {
+	    gimple_statement_omp_task *stmt
+	      = static_cast <gimple_statement_omp_task *> (x);
+	    gt_pch_nx_gimple_statement_base (stmt->body);
+	    gt_pch_n_9tree_node (stmt->clauses);
+	    gt_pch_n_9tree_node (stmt->child_fn);
+	    gt_pch_n_9tree_node (stmt->data_arg);
+	    gt_pch_n_9tree_node (stmt->copy_fn);
+	    gt_pch_n_9tree_node (stmt->arg_size);
+	    gt_pch_n_9tree_node (stmt->arg_align);
+	  }
+	  break;
+	case GSS_OMP_SECTIONS:
+	  {
+	    gimple_statement_omp_sections *stmt
+	      = static_cast <gimple_statement_omp_sections *> (x);
+	    gt_pch_nx_gimple_statement_base (stmt->body);
+	    gt_pch_n_9tree_node (stmt->clauses);
+	    gt_pch_n_9tree_node (stmt->control);
+	  }
+	  break;
+	case GSS_OMP_SINGLE:
+	  {
+	    gimple_statement_omp_single *stmt
+	      = static_cast <gimple_statement_omp_single *> (x);
+	    gt_pch_nx_gimple_statement_base (stmt->body);
+	    gt_pch_n_9tree_node (stmt->clauses);
+	  }
+	  break;
+	case GSS_OMP_CONTINUE:
+	  {
+	    gimple_statement_omp_continue *stmt
+	      = static_cast <gimple_statement_omp_continue *> (x);
+	    gt_pch_n_9tree_node (stmt->control_def);
+	    gt_pch_n_9tree_node (stmt->control_use);
+	  }
+	  break;
+	case GSS_OMP_ATOMIC_LOAD:
+	  {
+	    gimple_statement_omp_atomic_load *stmt
+	      = static_cast <gimple_statement_omp_atomic_load *> (x);
+	    gt_pch_n_9tree_node (stmt->rhs);
+	    gt_pch_n_9tree_node (stmt->lhs);
+	  }
+	  break;
+	case GSS_OMP_ATOMIC_STORE:
+	  {
+	    gimple_statement_omp_atomic_store *stmt
+	      = static_cast <gimple_statement_omp_atomic_store *> (x);
+	    gt_pch_n_9tree_node (stmt->val);
+	  }
+	  break;
+	case GSS_TRANSACTION:
+	  {
+	    gimple_statement_transaction *stmt
+	      = static_cast <gimple_statement_transaction *> (x);
+	    gt_pch_nx_gimple_statement_base (stmt->body);
+	    gt_pch_n_9tree_node (stmt->label);
+	  }
+	  break;
+	default:
+	  break;
+	}
+      x = x->next;
+    }
+}
+
+void
+gt_pch_nx (gimple gs, gt_pointer_operator op, void *cookie)
+{
+  op (&(gs->bb), cookie);
+  op (&(gs->next), cookie);
+  switch (gimple_statement_structure (gs))
+    {
+    case GSS_BASE:
+      break;
+    case GSS_WITH_OPS:
+      {
+	gimple_statement_with_ops *stmt
+	  = static_cast <gimple_statement_with_ops *> (gs);
+	size_t num = (size_t)(stmt->num_ops);
+	for (size_t i = 0; i != num; i++)
+	  op (&(stmt->op[i]), cookie);
+      }
+      break;
+    case GSS_WITH_MEM_OPS_BASE:
+      break;
+    case GSS_WITH_MEM_OPS:
+      {
+	gimple_statement_with_memory_ops *stmt
+	  = static_cast <gimple_statement_with_memory_ops *> (gs);
+	size_t num = (size_t)(stmt->num_ops);
+	for (size_t i = 0; i != num; i++)
+	  op (&(stmt->op[i]), cookie);
+      }
+      break;
+    case GSS_CALL:
+      {
+	gimple_statement_call *stmt
+	  = static_cast <gimple_statement_call *> (gs);
+	size_t num = (size_t)(stmt->num_ops);
+	op (&(stmt->call_used.vars), cookie);
+	op (&(stmt->call_clobbered.vars), cookie);
+	switch (stmt->subcode & GF_CALL_INTERNAL)
+	  {
+	  case 0:
+	    op (&(stmt->u.fntype), cookie);
+	    break;
+	  case GF_CALL_INTERNAL:
+	    break;
+	  default:
+	    break;
+	  }
+	for (size_t i = 0; i != num; i++)
+	  op (&(stmt->op[i]), cookie);
+      }
+      break;
+    case GSS_OMP:
+      {
+	gimple_statement_omp *stmt
+	  = static_cast <gimple_statement_omp *> (gs);
+	op (&(stmt->body), cookie);
+      }
+      break;
+    case GSS_BIND:
+      {
+	gimple_statement_bind *stmt
+	  = static_cast <gimple_statement_bind *> (gs);
+	op (&(stmt->vars), cookie);
+	op (&(stmt->block), cookie);
+	op (&(stmt->body), cookie);
+      }
+      break;
+    case GSS_CATCH:
+      {
+	gimple_statement_catch *stmt
+	  = static_cast <gimple_statement_catch *> (gs);
+	op (&(stmt->types), cookie);
+	op (&(stmt->handler), cookie);
+      }
+      break;
+    case GSS_EH_FILTER:
+      {
+	gimple_statement_eh_filter *stmt
+	  = static_cast <gimple_statement_eh_filter *> (gs);
+	op (&(stmt->types), cookie);
+	op (&(stmt->failure), cookie);
+      }
+      break;
+    case GSS_EH_MNT:
+      {
+	gimple_statement_eh_mnt *stmt
+	  = static_cast <gimple_statement_eh_mnt *> (gs);
+	op (&(stmt->fndecl), cookie);
+      }
+      break;
+    case GSS_EH_ELSE:
+      {
+	gimple_statement_eh_else*stmt
+	  = static_cast <gimple_statement_eh_else *> (gs);
+	op (&(stmt->n_body), cookie);
+	op (&(stmt->e_body), cookie);
+      }
+      break;
+    case GSS_PHI:
+      {
+	gimple_statement_phi *stmt
+	  = static_cast <gimple_statement_phi *> (gs);
+	size_t num = (size_t)(stmt->nargs);
+	op (&(stmt->result), cookie);
+	for (size_t i = 0; i != num; i++)
+	  op (&(stmt->args[i].def), cookie);
+      }
+      break;
+    case GSS_EH_CTRL:
+      break;
+    case GSS_TRY:
+      {
+	gimple_statement_try *stmt
+	  = static_cast <gimple_statement_try *> (gs);
+	op (&(stmt->eval), cookie);
+	op (&(stmt->cleanup), cookie);
+      }
+      break;
+    case GSS_WCE:
+      {
+	gimple_statement_wce *stmt
+	  = static_cast <gimple_statement_wce *> (gs);
+	op (&(stmt->cleanup), cookie);
+      }
+      break;
+    case GSS_ASM:
+      {
+	gimple_statement_asm *stmt
+	  = static_cast <gimple_statement_asm *> (gs);
+	size_t num = (size_t)(stmt->num_ops);
+	op (&(stmt->string), cookie);
+	for (size_t i = 0; i != num; i++)
+	  op (&(stmt->op[i]), cookie);
+      }
+      break;
+    case GSS_OMP_CRITICAL:
+      {
+	gimple_statement_omp_critical *stmt
+	  = static_cast <gimple_statement_omp_critical *> (gs);
+	op (&(stmt->body), cookie);
+	op (&(stmt->name), cookie);
+      }
+      break;
+    case GSS_OMP_FOR:
+      {
+	gimple_statement_omp_for *stmt
+	  = static_cast <gimple_statement_omp_for *> (gs);
+	size_t num = (size_t)(stmt->collapse);
+	op (&(stmt->body), cookie);
+	op (&(stmt->clauses), cookie);
+	if (stmt->iter != NULL) {
+	  for (size_t i = 0; i != num; i++) {
+	    op (&(stmt->iter[i].index), cookie);
+	    op (&(stmt->iter[i].initial), cookie);
+	    op (&(stmt->iter[i].final), cookie);
+	    op (&(stmt->iter[i].incr), cookie);
+	  }
+	  op (&(stmt->iter), cookie);
+	}
+	op (&(stmt->pre_body), cookie);
+      }
+      break;
+    case GSS_OMP_PARALLEL:
+      {
+	gimple_statement_omp_parallel *stmt
+	  = static_cast <gimple_statement_omp_parallel *> (gs);
+	op (&(stmt->body), cookie);
+	op (&(stmt->clauses), cookie);
+	op (&(stmt->child_fn), cookie);
+	op (&(stmt->data_arg), cookie);
+      }
+      break;
+    case GSS_OMP_TASK:
+      {
+	gimple_statement_omp_task *stmt
+	  = static_cast <gimple_statement_omp_task *> (gs);
+	op (&(stmt->body), cookie);
+	op (&(stmt->clauses), cookie);
+	op (&(stmt->child_fn), cookie);
+	op (&(stmt->data_arg), cookie);
+	op (&(stmt->copy_fn), cookie);
+	op (&(stmt->arg_size), cookie);
+	op (&(stmt->arg_align), cookie);
+      }
+      break;
+    case GSS_OMP_SECTIONS:
+      {
+	gimple_statement_omp_sections *stmt
+	  = static_cast <gimple_statement_omp_sections *> (gs);
+	op (&(stmt->body), cookie);
+	op (&(stmt->clauses), cookie);
+	op (&(stmt->control), cookie);
+      }
+      break;
+    case GSS_OMP_SINGLE:
+      {
+	gimple_statement_omp_single *stmt
+	  = static_cast <gimple_statement_omp_single *> (gs);
+	op (&(stmt->body), cookie);
+	op (&(stmt->clauses), cookie);
+      }
+      break;
+    case GSS_OMP_CONTINUE:
+      {
+	gimple_statement_omp_continue *stmt
+	  = static_cast <gimple_statement_omp_continue *> (gs);
+	op (&(stmt->control_def), cookie);
+	op (&(stmt->control_use), cookie);
+      }
+      break;
+    case GSS_OMP_ATOMIC_LOAD:
+      {
+	gimple_statement_omp_atomic_load *stmt
+	  = static_cast <gimple_statement_omp_atomic_load *> (gs);
+	op (&(stmt->rhs), cookie);
+	op (&(stmt->lhs), cookie);
+      }
+      break;
+    case GSS_OMP_ATOMIC_STORE:
+      {
+	gimple_statement_omp_atomic_store *stmt
+	  = static_cast <gimple_statement_omp_atomic_store *> (gs);
+	op (&(stmt->val), cookie);
+      }
+      break;
+    case GSS_TRANSACTION:
+      {
+	gimple_statement_transaction *stmt
+	  = static_cast <gimple_statement_transaction *> (gs);
+	op (&(stmt->body), cookie);
+	op (&(stmt->label), cookie);
+      }
+      break;
+    default:
+      break;
+    }
+}
+
+
 #include "gt-gimple.h"
diff --git a/gcc/gimple.h b/gcc/gimple.h
index daab54e..9b428eb 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -222,6 +222,12 @@  struct GTY((user)) gimple_statement_base {
   gimple GTY((skip)) prev;
 };
 
+/* GTY((user)) hooks for gimple, called once per-traversal.  */
+void gt_ggc_mx (gimple gs);
+void gt_pch_nx (gimple gs);
+void gt_pch_nx (gimple gs, gt_pointer_operator op, void *cookie);
+
+
 
 /* Base structure for tuples with operands.  */
 
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index af8685c..185c072 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -8291,7 +8291,6 @@  make_pass_warn_unused_result (gcc::context *ctxt)
 /* Garbage collection support for edge_def.  */
 
 extern void gt_ggc_mx (tree&);
-extern void gt_ggc_mx (gimple&);
 extern void gt_ggc_mx (rtx&);
 extern void gt_ggc_mx (basic_block&);
 
@@ -8302,7 +8301,7 @@  gt_ggc_mx (edge_def *e)
   gt_ggc_mx (e->src);
   gt_ggc_mx (e->dest);
   if (current_ir_type () == IR_GIMPLE)
-    gt_ggc_mx (e->insns.g);
+    gt_ggc_mx_gimple_statement_base (e->insns.g);
   else
     gt_ggc_mx (e->insns.r);
   gt_ggc_mx (block);
@@ -8311,7 +8310,6 @@  gt_ggc_mx (edge_def *e)
 /* PCH support for edge_def.  */
 
 extern void gt_pch_nx (tree&);
-extern void gt_pch_nx (gimple&);
 extern void gt_pch_nx (rtx&);
 extern void gt_pch_nx (basic_block&);
 
@@ -8322,7 +8320,7 @@  gt_pch_nx (edge_def *e)
   gt_pch_nx (e->src);
   gt_pch_nx (e->dest);
   if (current_ir_type () == IR_GIMPLE)
-    gt_pch_nx (e->insns.g);
+    gt_pch_nx_gimple_statement_base (e->insns.g);
   else
     gt_pch_nx (e->insns.r);
   gt_pch_nx (block);