Quoting Bernd Schmidt <bernds_...@t-online.de>:
2009-02-24 J"orn Rennecke <joern.renne...@arc.com>
* loop-doloop.c (doloop_valid_p): Rename to:
(validize_doloop). Try to fix up loops with conditons for infinite
looping by enclosing them in an outer loop.
Changed caller.
(add_test): Add new parameter edgep. Changed caller.
This looks interesting, but unless I read the svn log incorrectly, the
arc branches have all patches applied in a single commit, which isn't
exactly useful. Do you have them broken-out somewhere?
I've appended the sliced & diced diff - not separately tested, though.
Please let me know if there are any problems.
2009-02-24 J"orn Rennecke <joern.renne...@arc.com>
* loop-doloop.c (doloop_valid_p): Rename to:
(validize_doloop). Try to fix up loops with conditons for infinite
looping by enclosing them in an outer loop.
Changed caller.
(add_test): Add new parameter edgep. Changed caller.
Index: loop-doloop.c
===================================================================
--- loop-doloop.c (revision 145497)
+++ loop-doloop.c (revision 145498)
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.
#include "output.h"
#include "params.h"
#include "target.h"
+#include "optabs.h"
/* This module is used to modify loops with a determinable number of
iterations to use special low-overhead looping instructions.
@@ -194,22 +195,92 @@ doloop_condition_get (rtx doloop_pat)
return 0;
}
-/* Return nonzero if the loop specified by LOOP is suitable for
- the use of special low-overhead looping instructions. DESC
- describes the number of iterations of the loop. */
+static bool add_test (rtx cond, edge *e, basic_block dest, edge *);
-static bool
-doloop_valid_p (struct loop *loop, struct niter_desc *desc)
+/* Check if the loop specified by LOOP is suitable for
+ the use of special low-overhead looping instructions.
+ If necessary to properly implement infinite loops, this may cause
+ a new enclosing loop to be formed. Returns the (possible changed)
+ loop structure pointer on success, else NULL.
+ DESC describes the number of iterations of the loop. */
+
+static struct loop *
+validize_doloop (struct loop *loop, struct niter_desc *desc)
{
basic_block *body = get_loop_body (loop), bb;
rtx insn;
unsigned i;
bool result = true;
+ rtx list;
+ edge out_edge;
/* Check for loops that may not terminate under special conditions. */
if (!desc->simple_p
|| desc->assumptions
- || desc->infinite)
+ || (desc->infinite
+ && (EDGE_COUNT (loop->latch->preds) != 1
+ || !optimize_loop_for_speed_p (loop))))
+ result = false;
+ if (desc->infinite)
+ {
+ edge e, latch_in;
+ edge_iterator ei;
+ rtx insn;
+
+ /* We want to set out_edge to the edge that is used to exit the loop
+ if the loop count is exhausted. For now, only handle the case
+ of a single exit. */
+ out_edge = NULL;
+ if (single_pred_p (loop->latch))
+ {
+ latch_in = single_pred_edge (loop->latch);
+ FOR_EACH_EDGE (e, ei, latch_in->src->succs)
+ if (e == latch_in)
+ ; /* do nothing */
+ else if (!out_edge)
+ out_edge = e;
+ else
+ result = false;
+ }
+ if (!out_edge)
+ result = false;
+ else if (dump_file)
+ fprintf (dump_file, "Doloop: considering putting infinite loop"
+ " instructions on edge from %d to %d.\n",
+ out_edge->src->index, out_edge->dest->index);
+ /* The (non-jump) instructions in the current loop latch shoould be
+ copied into the new loop latch cf. gcc.c-torture/execute/pr27285.c .
+ For now, just punt when we see any insns in the latch. */
+ FOR_BB_INSNS (loop->latch, insn)
+ if (NONJUMP_INSN_P (insn))
+ {
+ result = false;
+ break;
+ }
+
+ }
+ /* check_simple_exit can create conditions that do_compare_and_jump_rtx
+ can't grok. */
+ for (list = desc->infinite; list; list = XEXP (list, 1))
+ {
+ rtx cond = XEXP (list, 0);
+ enum machine_mode mode;
+
+ if (!BINARY_P (cond))
+ {
+ result = false;
+ break;
+ }
+ mode = GET_MODE (XEXP (cond, 0));
+ if (mode == VOIDmode)
+ mode = GET_MODE (XEXP (cond, 1));
+
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && !can_compare_p (GET_CODE (cond), mode, ccp_jump)
+ && !COMPARISON_P (cond))
+ result = false;
+ }
+ if (!result)
{
/* There are some cases that would require a special attention.
For example if the comparison is LEU and the comparison value
@@ -261,27 +332,84 @@ doloop_valid_p (struct loop *loop, struc
}
}
}
- result = true;
+ if (desc->infinite)
+ {
+ basic_block header = loop->header;
+ basic_block latch;
+ struct loop *new_loop;
+
+ gcc_assert (loops_state_satisfies_p (LOOPS_HAVE_PREHEADERS));
+ {
+ edge latch_edge = single_succ_edge (loop->latch);
+ edge in_edge;
+
+ gcc_assert (EDGE_COUNT (header->preds) == 2);
+ gcc_assert (latch_edge->dest == header);
+ if (dump_file)
+ fprintf (dump_file,
+ "Doloop: infinite loop generation: latch %d header %d\n",
+ loop->latch->index, header->index);
+ in_edge = EDGE_PRED (header, 0);
+ if (in_edge == latch_edge)
+ in_edge = EDGE_PRED (header, 1);
+ else
+ gcc_assert (latch_edge == EDGE_PRED (header, 1));
+ gcc_assert (in_edge != out_edge);
+ header = split_edge (in_edge);
+ set_immediate_dominator (CDI_DOMINATORS, loop->header, header);
+ remove_bb_from_loops (header);
+ add_bb_to_loop (header, loop);
+#if 0 /* For debugging, insert a marker insn. */
+ emit_insn_after (gen_unimp_s (GEN_INT (1)), BB_END (header));
+#endif
+ }
+ for (latch = header, list = desc->infinite; list; list = XEXP (list, 1))
+ {
+ edge new_latch_edge = out_edge;
+
+ add_test (XEXP (list, 0), &out_edge, latch, &new_latch_edge);
+ remove_bb_from_loops (out_edge->src);
+ add_bb_to_loop (out_edge->src, loop);
+ if (latch == header)
+ {
+ latch = split_edge (new_latch_edge);
+ remove_bb_from_loops (latch);
+ add_bb_to_loop (latch, loop);
+#if 0 /* For debugging, insert a marker insn. */
+ emit_insn_after (gen_trap_s (GEN_INT (42)), BB_END (latch));
+#endif
+ }
+ }
+ new_loop = alloc_loop ();
+ new_loop->header = loop->header;
+ new_loop->latch = loop->latch;
+ loop->header = header;
+ loop->latch = latch;
+ add_loop (new_loop, loop);
+ loop = new_loop;
+ }
cleanup:
free (body);
- return result;
+ return result ? loop : 0;
}
/* Adds test of COND jumping to DEST on edge *E and set *E to the new fallthru
edge. If the condition is always false, do not do anything. If it is
always
true, redirect E to DEST and return false. In all other cases, true is
- returned. */
+ returned.
+ If EDGEP is non-null, assign the any newly created edge to it. */
static bool
-add_test (rtx cond, edge *e, basic_block dest)
+add_test (rtx cond, edge *e, basic_block dest, edge *edgep)
{
rtx seq, jump, label;
enum machine_mode mode;
rtx op0 = XEXP (cond, 0), op1 = XEXP (cond, 1);
enum rtx_code code = GET_CODE (cond);
basic_block bb;
+ edge new_edge;
mode = GET_MODE (XEXP (cond, 0));
if (mode == VOIDmode)
@@ -325,7 +453,9 @@ add_test (rtx cond, edge *e, basic_block
LABEL_NUSES (label)++;
- make_edge (bb, dest, (*e)->flags & ~EDGE_FALLTHRU);
+ new_edge = make_edge (bb, dest, (*e)->flags & ~EDGE_FALLTHRU);
+ if (edgep)
+ *edgep = new_edge;
return true;
}
@@ -448,7 +578,7 @@ doloop_modify (struct loop *loop, struct
te = single_succ_edge (preheader);
for (; ass; ass = XEXP (ass, 1))
- if (!add_test (XEXP (ass, 0), &te, set_zero))
+ if (!add_test (XEXP (ass, 0), &te, set_zero, NULL))
break;
if (ass)
@@ -565,7 +697,8 @@ doloop_optimize (struct loop *loop)
desc = get_simple_loop_desc (loop);
/* Check that loop is a candidate for a low-overhead looping insn. */
- if (!doloop_valid_p (loop, desc))
+ loop = validize_doloop (loop, desc);
+ if (!loop)
{
if (dump_file)
fprintf (dump_file,