Quoting Bernd Schmidt <[email protected]>:
2009-02-24 J"orn Rennecke <[email protected]>* 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 <[email protected]> * 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,
