Hello,
SMS currently works only on single-basic-block loops. This simplifies
the task of software pipelining. PR34263 is an example where outof-ssa
creates a non-empty latch block for a single-basic-block loop and thus
prevents SMS to be applied on it. This issue was raised in the past
(http://gcc.gnu.org/ml/gcc-patches/2005-11/msg01971.html) but I am not
sure what is the best approach to address it. Cleaning-up those latch
blocks for the propose of restoring the single-basic-block loop should
be helpful in general (and not only in the SMS perspective).
So, we can address this inside SMS or alternatively in outof-ssa as in the
attached patch (which was originally written by Andrew Pinski for PR19038
and rewritten by Mircea, it also passes bootstrap and regtest on ppc64).
Thanks,
Revital
(See attached file: patch_empty_latch_2_12.txt)
Index: tree-outof-ssa.c
===================================================================
--- tree-outof-ssa.c (revision 130511)
+++ tree-outof-ssa.c (working copy)
@@ -871,6 +871,17 @@
BITMAP_FREE (leader_has_match);
}
+static tree
+contains_tree_r (tree *tp, int *walk_subtrees, void *data)
+{
+ if (*tp == data)
+ {
+ *walk_subtrees = 0;
+ return data;
+ }
+ else
+ return NULL_TREE;
+}
/* Look at all the incoming edges to block BB, and decide where the best place
to insert the stmts on each edge are, and perform those insertions. */
@@ -944,7 +955,111 @@
if (count < 2)
{
if (single_edge)
- bsi_commit_one_edge_insert (single_edge, NULL);
+ {
+ /* Loop back edges are special and should be handled that way. */
+ if (single_edge->dest == single_edge->src)
+ {
+ bool do_it = true;
+ bool before = false;
+ tree stmts = PENDING_STMT (single_edge);
+ basic_block b_exit, b_pheader, b_loop = single_edge->src;
+ edge_iterator ei;
+ edge e;
+ block_stmt_iterator bsi_exit;
+
+ if (EDGE_COUNT (b_loop->succs) != 2
+ || EDGE_COUNT (b_loop->preds) != 2)
+ do_it = false;
+
+ FOR_EACH_EDGE (e, ei, b_loop->succs)
+ if (e->dest != b_loop)
+ break;
+
+ b_exit = e->dest;
+
+ if (EDGE_COUNT (b_exit->preds) != 1 || PENDING_STMT (e))
+ do_it = false;
+
+ FOR_EACH_EDGE (e, ei, b_loop->preds)
+ if (e->src != b_loop)
+ break;
+
+ b_pheader = e->src;
+
+ if (b_exit == b_pheader
+ || b_exit == b_loop || b_pheader == b_loop)
+ do_it = false;
+
+ bsi_exit = bsi_after_labels (b_exit);
+ bsi = bsi_last (single_edge->src);
+ stmt = bsi_stmt (bsi);
+
+ /* Check if it is legal to do it. */
+ if (TREE_CODE (stmt) == COND_EXPR)
+ {
+ tree expr = COND_EXPR_COND (stmt);
+ tree_stmt_iterator tsi;
+ before = true;
+
+ for (tsi = tsi_start (stmts); !tsi_end_p (tsi);
+ tsi_next (&tsi))
+ {
+ tree stmt1 = tsi_stmt (tsi);
+ tree var;
+
+ if (TREE_CODE (stmt1) != GIMPLE_MODIFY_STMT)
+ {
+ print_generic_stmt (dump_file, stmt1, TDF_VOPS);
+ do_it = false;
+ break;
+ }
+ var = GIMPLE_STMT_OPERAND (stmt1, 0);
+ if (TREE_THIS_VOLATILE (var)
+ || TYPE_VOLATILE (TREE_TYPE (var))
+ || walk_tree (&expr, contains_tree_r, var, NULL))
+ {
+ do_it = false;
+ break;
+ }
+ }
+ }
+ /* Insert the statements right before */
+ if (do_it)
+ {
+ tree_stmt_iterator tsi;
+
+ for (tsi = tsi_start (stmts); !tsi_end_p (tsi);
+ tsi_next (&tsi))
+ {
+ tree stmt1 = tsi_stmt (tsi);
+ tree var, tmp_var, copy;
+
+ var = GIMPLE_STMT_OPERAND (stmt1, 0);
+ tmp_var = create_temp (var);
+ copy =
+ build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (tmp_var),
+ tmp_var, var);
+ set_is_used (tmp_var);
+ if (before)
+ bsi_insert_before (&bsi, copy, BSI_SAME_STMT);
+ else
+ bsi_insert_after (&bsi, copy, BSI_NEW_STMT);
+ copy =
+ build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (tmp_var), var,
+ tmp_var);
+ bsi_insert_before (&bsi_exit, copy, BSI_SAME_STMT);
+
+ }
+ PENDING_STMT (single_edge) = 0;
+ if (before)
+ bsi_insert_before (&bsi, stmts, BSI_NEW_STMT);
+ else
+ bsi_insert_after (&bsi, stmts, BSI_NEW_STMT);
+ return;
+ }
+ }
+ bsi_commit_one_edge_insert (single_edge, NULL);
+ }
return;
}