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,

Reply via email to