#include "timevar.h"
#include "df.h"
#include "tree-pass.h"
+#include "params.h"
static void *df_get_bb_info (struct dataflow *, unsigned int);
static void df_set_bb_info (struct dataflow *, unsigned int, void *);
}
+
+/* This will free "pending". */
+static void
+df_worklist_dataflow_overeager (struct dataflow *dataflow,
+ bitmap pending,
+ sbitmap considered,
+ int *blocks_in_postorder,
+ unsigned *bbindex_to_postorder)
+{
+ enum df_flow_dir dir = dataflow->problem->dir;
+ int count = 0;
+
+ while (!bitmap_empty_p (pending))
+ {
+ unsigned bb_index;
+ int index;
+ count++;
+
+ index = bitmap_first_set_bit (pending);
+ bitmap_clear_bit (pending, index);
+
+ bb_index = blocks_in_postorder[index];
+
+ if (dir == DF_FORWARD)
+ df_worklist_propagate_forward (dataflow, bb_index,
+ bbindex_to_postorder,
+ pending, considered);
+ else
+ df_worklist_propagate_backward (dataflow, bb_index,
+ bbindex_to_postorder,
+ pending, considered);
+ }
+
+ BITMAP_FREE (pending);
+
+ /* Dump statistics. */
+ if (dump_file)
+ fprintf (dump_file, "df_worklist_dataflow_overeager:"
+ "n_basic_blocks %d n_edges %d"
+ " count %d (%5.2g)\n",
+ n_basic_blocks, n_edges,
+ count, count / (float)n_basic_blocks);
+}
+
+static void
+df_worklist_dataflow_doublequeue (struct dataflow *dataflow,
+ bitmap pending,
+ sbitmap considered,
+ int *blocks_in_postorder,
+ unsigned *bbindex_to_postorder)
+{
+ enum df_flow_dir dir = dataflow->problem->dir;
+ int dcount = 0;
+ bitmap worklist = BITMAP_ALLOC (&df_bitmap_obstack);
+
+ /* Double-queueing. Worklist is for the current iteration,
+ and pending is for the next. */
+ while (!bitmap_empty_p (pending))
+ {
+ /* Swap pending and worklist. */
+ bitmap temp = worklist;
+ worklist = pending;
+ pending = temp;
+
+ do
+ {
+ int index;
+ unsigned bb_index;
+ dcount++;
+
+ index = bitmap_first_set_bit (worklist);
+ bitmap_clear_bit (worklist, index);
+
+ bb_index = blocks_in_postorder[index];
+
+ if (dir == DF_FORWARD)
+ df_worklist_propagate_forward (dataflow, bb_index,
+ bbindex_to_postorder,
+ pending, considered);
+ else
+ df_worklist_propagate_backward (dataflow, bb_index,
+ bbindex_to_postorder,
+ pending, considered);
+ }
+ while (!bitmap_empty_p (worklist));
+ }
+
+ BITMAP_FREE (worklist);
+ BITMAP_FREE (pending);
+
+ /* Dump statistics. */
+ if (dump_file)
+ fprintf (dump_file, "df_worklist_dataflow_doublequeue:"
+ "n_basic_blocks %d n_edges %d"
+ " count %d (%5.2g)\n",
+ n_basic_blocks, n_edges,
+ dcount, dcount / (float)n_basic_blocks);
+}
+
/* Worklist-based dataflow solver. It uses sbitmap as a worklist,
with "n"-th bit representing the n-th block in the reverse-postorder order.
This is so-called over-eager algorithm where it propagates
iterative algorithm by some margin overall.
Note that this is slightly different from the traditional textbook worklist solver,
in that the worklist is effectively sorted by the reverse postorder.
- For CFGs with no nested loops, this is optimal. */
+ For CFGs with no nested loops, this is optimal.
+
+ The overeager algorithm while works well for typical inputs,
+ it could degenerate into excessive iterations given CFGs with high loop nests
+ and unstructured loops. To cap the excessive iteration on such case,
+ we switch to double-queueing when the original algorithm seems to
+ get into such.
+ */
void
df_worklist_dataflow (struct dataflow *dataflow,
bitmap_set_bit (pending, i);
}
+ /* Initialize the problem. */
if (dataflow->problem->init_fun)
dataflow->problem->init_fun (blocks_to_consider);
- while (!bitmap_empty_p (pending))
+ /* Solve it. Determine the solving algorithm
+ based on a simple heuristic. */
+ if (n_edges > PARAM_VALUE (PARAM_DF_DOUBLE_QUEUE_THRESHOLD_FACTOR)
+ * n_basic_blocks)
{
- unsigned bb_index;
-
- index = bitmap_first_set_bit (pending);
- bitmap_clear_bit (pending, index);
-
- bb_index = blocks_in_postorder[index];
-
- if (dir == DF_FORWARD)
- df_worklist_propagate_forward (dataflow, bb_index,
- bbindex_to_postorder,
- pending, considered);
- else
- df_worklist_propagate_backward (dataflow, bb_index,
- bbindex_to_postorder,
- pending, considered);
+ /* High average connectivity, meaning dense graph
+ with more likely deep nested loops
+ or unstructured loops. */
+ df_worklist_dataflow_doublequeue (dataflow, pending, considered,
+ blocks_in_postorder,
+ bbindex_to_postorder);
+ }
+ else
+ {
+ /* Most inputs fall into this case
+ with relatively flat or structured CFG. */
+ df_worklist_dataflow_overeager (dataflow, pending, considered,
+ blocks_in_postorder,
+ bbindex_to_postorder);
}
- BITMAP_FREE (pending);
sbitmap_free (considered);
free (bbindex_to_postorder);
}