Optimize df_worklist_dataflow

Steven Bosscher stevenb.gcc@gmail.com
Sat Jun 12 18:08:00 GMT 2010


On Sat, Jun 12, 2010 at 3:40 PM, Jan Hubicka <hubicka@ucw.cz> wrote:


> Everythign in the main dataflow loop seems performance critical, so one age
> is stored in vector and the last change age (that is accessed more times)
> in the AUX field of BB structure.

Why not store both in a vector?  I really dislike using the void*
pointer aux field for an integer value, casting back-and-forth from
(void*) to (size_t).


>        * df-problems.c (df_rd_confluence_n, df_lr_confluence_n, df_live_confluence_n,
>        df_byte_lr_confluence_n, df_md_confluence_n): Return true if something changed.
>        * df.h (df_confluence_function_n): Return bool.
>        * df-core.c (df_worklist_propagate_forward, df_worklist_propagate_backward):
>        track changes and ages.

Nit: s/track/Track/

You should also explain the algorithmic changes you're making. This
"age" trick is not found in text-book dataflow solvers, so it's not as
obvious as the existing code. Therefore, please add a not-too-small
comment explaining what the algorithm is doing. Probably belongs
somewhere before df_worklist_dataflow().


> -static void
> +static bool
>  df_lr_confluence_n (edge e)
...
> -  bitmap_ior_into (op1, &df->hardware_regs_used);
> +  return bitmap_ior_into (op1, &df->hardware_regs_used) || changed;

For readability I prefer,
  changed |= bitmap_ior_into (op1, &df->hardware_regs_used);
  return changed;


> +static bool
>  df_byte_lr_confluence_n (edge e)
...
> -    bitmap_ior_and_compl_into (op1, op2, &problem_data->invalidated_by_call);
> +    changed = bitmap_ior_and_compl_into (op1, op2, &problem_data->invalidated_by_call);

Long line, please break it.

>   else
> -    bitmap_ior_into (op1, op2);
> +    changed = bitmap_ior_into (op1, op2);
>
> -  bitmap_ior_into (op1, &problem_data->hardware_regs_used);
> +  return bitmap_ior_into (op1, &problem_data->hardware_regs_used) || changed;

Same comment as for df_lr_confluence_n: please "return changed;" on a
separate line.


> +static bool
>  df_md_confluence_n (edge e)
...
>   if (e->flags & EDGE_EH)
> -    bitmap_ior_and_compl_into (op1, op2, regs_invalidated_by_call_regset);
> +    return bitmap_ior_and_compl_into (op1, op2, regs_invalidated_by_call_regset);

Another long line.


>  /* Free all storage associated with the problem.  */
> Index: df.h
> ===================================================================
> --- df.h        (revision 160661)
> +++ df.h        (working copy)
> @@ -223,7 +223,7 @@ typedef void (*df_dataflow_function) (st
>  typedef void (*df_confluence_function_0) (basic_block);
>
>  /* Confluence operator for blocks with 1 or more out (or in) edges.  */
> -typedef void (*df_confluence_function_n) (edge);
> +typedef bool (*df_confluence_function_n) (edge);

Already mentioned: Please add a comment what the return value should be.


>  /* Transfer function for blocks.  */
>  typedef bool (*df_transfer_function) (int);
> Index: df-core.c
> ===================================================================
> --- df-core.c   (revision 160661)
> +++ df-core.c   (working copy)
> @@ -858,28 +858,35 @@ struct rtl_opt_pass pass_df_finish =
>    and set bits on for successors in PENDING
>    if the out set of the dataflow has changed. */
>
> -static void
> +static bool

Document return value in the pre-function comment.

>  df_worklist_propagate_forward (struct dataflow *dataflow,
>                                unsigned bb_index,
>                                unsigned *bbindex_to_postorder,
>                                bitmap pending,
> -                               sbitmap considered)
> +                               sbitmap considered,
> +                              size_t age)

Document the new parameter in the pre-function comment.


>  {
>   edge e;
>   edge_iterator ei;
>   basic_block bb = BASIC_BLOCK (bb_index);
> +  bool changed = !age;
>
>   /*  Calculate <conf_op> of incoming edges.  */
>   if (EDGE_COUNT (bb->preds) > 0)
>     FOR_EACH_EDGE (e, ei, bb->preds)
>       {
> -        if (TEST_BIT (considered, e->src->index))
> -          dataflow->problem->con_fun_n (e);
> +        if ((age <= (size_t)e->src->aux)

Yuck!


> +            && TEST_BIT (considered, e->src->index))
> +          changed |= dataflow->problem->con_fun_n (e);
>       }
>   else if (dataflow->problem->con_fun_0)
> -    dataflow->problem->con_fun_0 (bb);
> +    {
> +      dataflow->problem->con_fun_0 (bb);
> +      changed = true;

I guess it's not very important for what you're trying to achieve, but
why do you have to set changed = true always after con_fun_0? It makes
you run the transfer function and propagated "changed-ness" all over.
So IIUC, e.g. for a forward propagation that starts with a maximum set
you always propagate changed to all successors.

Am I missing something?


> -static void
> +static bool
>  df_worklist_propagate_backward (struct dataflow *dataflow,
>                                 unsigned bb_index,
>                                 unsigned *bbindex_to_postorder,
>                                 bitmap pending,
> -                                sbitmap considered)
> +                                sbitmap considered,
> +                               size_t age)

Return value and new age argument should be documented.


> +DEF_VEC_I(size_t);
> +DEF_VEC_ALLOC_I(size_t,heap);

> @@ -941,46 +960,65 @@ df_worklist_dataflow_doublequeue (struct
>                                  bitmap pending,
>                                   sbitmap considered,
>                                   int *blocks_in_postorder,
> -                                 unsigned *bbindex_to_postorder)
> +                                 unsigned *bbindex_to_postorder,
> +                                 int n_blocks)

Document n_blocks please.


Looks OK to me otherwise.

Ciao!
Steven



More information about the Gcc-patches mailing list