[3] Advanced Compiler Design and Implementation,
Steven Muchnick, Morgan Kaufmann, 1997, Section 12.6 */
-/* Worklist of control flow edge destinations. This contains
+/* Worklists of control flow edge destinations. This contains
the CFG order number of the blocks so we can iterate in CFG
- order by visiting in bit-order. */
+ order by visiting in bit-order. We use two worklists to
+ first make forward progress before iterating. */
static bitmap cfg_blocks;
+static bitmap cfg_blocks_back;
static int *bb_to_cfg_order;
static int *cfg_order_to_bb;
-/* Worklist of SSA edges which will need reexamination as their
+/* Worklists of SSA edges which will need reexamination as their
definition has changed. SSA edges are def-use edges in the SSA
web. For each D-U edge, we store the target statement or PHI node
- UID in a bitmap. UIDs order stmts in execution order. */
+ UID in a bitmap. UIDs order stmts in execution order. We use
+ two worklists to first make forward progress before iterating. */
static bitmap ssa_edge_worklist;
+static bitmap ssa_edge_worklist_back;
static vec<gimple *> uid_to_stmt;
-/* Return true if the block worklist empty. */
-
-static inline bool
-cfg_blocks_empty_p (void)
-{
- return bitmap_empty_p (cfg_blocks);
-}
-
-
-/* Add a basic block to the worklist. The block must not be the ENTRY
- or EXIT block. */
-
-static void
-cfg_blocks_add (basic_block bb)
-{
- gcc_assert (bb != ENTRY_BLOCK_PTR_FOR_FN (cfun)
- && bb != EXIT_BLOCK_PTR_FOR_FN (cfun));
- bitmap_set_bit (cfg_blocks, bb_to_cfg_order[bb->index]);
-}
-
-
-/* Remove a block from the worklist. */
-
-static basic_block
-cfg_blocks_get (void)
-{
- gcc_assert (!cfg_blocks_empty_p ());
- int order_index = bitmap_first_set_bit (cfg_blocks);
- bitmap_clear_bit (cfg_blocks, order_index);
- return BASIC_BLOCK_FOR_FN (cfun, cfg_order_to_bb [order_index]);
-}
+/* Current RPO index in the iteration. */
+static int curr_order;
/* We have just defined a new value for VAR. If IS_VARYING is true,
& EDGE_EXECUTABLE))
continue;
- if (prop_simulate_again_p (use_stmt)
- && bitmap_set_bit (ssa_edge_worklist, gimple_uid (use_stmt)))
+ if (!prop_simulate_again_p (use_stmt))
+ continue;
+
+ bitmap worklist;
+ if (bb_to_cfg_order[gimple_bb (use_stmt)->index] < curr_order)
+ worklist = ssa_edge_worklist_back;
+ else
+ worklist = ssa_edge_worklist;
+ if (bitmap_set_bit (worklist, gimple_uid (use_stmt)))
{
uid_to_stmt[gimple_uid (use_stmt)] = use_stmt;
if (dump_file && (dump_flags & TDF_DETAILS))
e->flags |= EDGE_EXECUTABLE;
- cfg_blocks_add (bb);
+ int bb_order = bb_to_cfg_order[bb->index];
+ if (bb_order < curr_order)
+ bitmap_set_bit (cfg_blocks_back, bb_order);
+ else
+ bitmap_set_bit (cfg_blocks, bb_order);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Adding destination of edge (%d -> %d) to worklist\n",
}
}
-/* Process an SSA edge worklist. WORKLIST is the SSA edge worklist to
- drain. This pops statements off the given WORKLIST and processes
- them until one statement was simulated or there are no more statements
- on WORKLIST. We take a pointer to WORKLIST because it may be reallocated
- when an SSA edge is added to it in simulate_stmt. Return true if a stmt
- was simulated. */
-
-void
-ssa_propagation_engine::process_ssa_edge_worklist (void)
-{
- /* Process the next entry from the worklist. */
- unsigned stmt_uid = bitmap_first_set_bit (ssa_edge_worklist);
- bitmap_clear_bit (ssa_edge_worklist, stmt_uid);
- gimple *stmt = uid_to_stmt[stmt_uid];
-
- /* We should not have stmts in not yet simulated BBs on the worklist. */
- gcc_assert (gimple_bb (stmt)->flags & BB_VISITED);
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "\nSimulating statement: ");
- print_gimple_stmt (dump_file, stmt, 0, dump_flags);
- }
-
- simulate_stmt (stmt);
-}
-
/* Simulate the execution of BLOCK. Evaluate the statement associated
with each variable reference inside the block. */
/* Worklists of SSA edges. */
ssa_edge_worklist = BITMAP_ALLOC (NULL);
+ ssa_edge_worklist_back = BITMAP_ALLOC (NULL);
/* Worklist of basic-blocks. */
bb_to_cfg_order = XNEWVEC (int, last_basic_block_for_fn (cfun) + 1);
for (int i = 0; i < n; ++i)
bb_to_cfg_order[cfg_order_to_bb[i]] = i;
cfg_blocks = BITMAP_ALLOC (NULL);
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- dump_immediate_uses (dump_file);
+ cfg_blocks_back = BITMAP_ALLOC (NULL);
/* Initially assume that every edge in the CFG is not executable.
(including the edges coming out of the entry block). Mark blocks
ssa_prop_fini (void)
{
BITMAP_FREE (cfg_blocks);
+ BITMAP_FREE (cfg_blocks_back);
free (bb_to_cfg_order);
free (cfg_order_to_bb);
BITMAP_FREE (ssa_edge_worklist);
+ BITMAP_FREE (ssa_edge_worklist_back);
uid_to_stmt.release ();
}
{
ssa_prop_init ();
- /* Iterate until the worklists are empty. */
- while (! cfg_blocks_empty_p ()
- || ! bitmap_empty_p (ssa_edge_worklist))
+ curr_order = 0;
+
+ /* Iterate until the worklists are empty. We iterate both blocks
+ and stmts in RPO order, using sets of two worklists to first
+ complete the current iteration before iterating over backedges. */
+ while (1)
{
- /* First simulate whole blocks. */
- if (! cfg_blocks_empty_p ())
+ int next_block_order = (bitmap_empty_p (cfg_blocks)
+ ? -1 : bitmap_first_set_bit (cfg_blocks));
+ int next_stmt_uid = (bitmap_empty_p (ssa_edge_worklist)
+ ? -1 : bitmap_first_set_bit (ssa_edge_worklist));
+ if (next_block_order == -1 && next_stmt_uid == -1)
{
- /* Pull the next block to simulate off the worklist. */
- basic_block dest_block = cfg_blocks_get ();
- simulate_block (dest_block);
+ if (bitmap_empty_p (cfg_blocks_back)
+ && bitmap_empty_p (ssa_edge_worklist_back))
+ break;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Regular worklists empty, now processing "
+ "backedge destinations\n");
+ std::swap (cfg_blocks, cfg_blocks_back);
+ std::swap (ssa_edge_worklist, ssa_edge_worklist_back);
continue;
}
- /* Then simulate from the SSA edge worklist. */
- process_ssa_edge_worklist ();
+ int next_stmt_bb_order = -1;
+ gimple *next_stmt = NULL;
+ if (next_stmt_uid != -1)
+ {
+ next_stmt = uid_to_stmt[next_stmt_uid];
+ next_stmt_bb_order = bb_to_cfg_order[gimple_bb (next_stmt)->index];
+ }
+
+ /* Pull the next block to simulate off the worklist if it comes first. */
+ if (next_block_order != -1
+ && (next_stmt_bb_order == -1
+ || next_block_order <= next_stmt_bb_order))
+ {
+ curr_order = next_block_order;
+ bitmap_clear_bit (cfg_blocks, next_block_order);
+ basic_block bb
+ = BASIC_BLOCK_FOR_FN (cfun, cfg_order_to_bb [next_block_order]);
+ simulate_block (bb);
+ }
+ /* Else simulate from the SSA edge worklist. */
+ else
+ {
+ curr_order = next_stmt_bb_order;
+ bitmap_clear_bit (ssa_edge_worklist, next_stmt_uid);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nSimulating statement: ");
+ print_gimple_stmt (dump_file, next_stmt, 0, dump_flags);
+ }
+ simulate_stmt (next_stmt);
+ }
}
ssa_prop_fini ();