re PR rtl-optimization/11634 ([hppa] ICE in verify_local_live_at_start, at flow.c...
authorRoger Sayle <roger@eyesopen.com>
Tue, 2 Dec 2003 01:43:58 +0000 (01:43 +0000)
committerRoger Sayle <sayle@gcc.gnu.org>
Tue, 2 Dec 2003 01:43:58 +0000 (01:43 +0000)
PR optimization/11634
* recog.c (split_insn): Factor test of INSN_P and handling of
set_noop_p out of here into the two callers.
(split_all_insns): Add INSN_P test and set_noop_p handling here.
If deleting a no-op set after reload that has a REG_UNUSED note,
mark the basic block as changed and recalculate life information.
(split_all_insns_noflow): Add INSN_P test and set_noop_p handling
here.

* gcc.dg/20031201-2.c: New test case.

From-SVN: r74145

gcc/ChangeLog
gcc/recog.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/20031201-2.c [new file with mode: 0644]

index 3f755a6619041a0fbd6a173c27218ecf4488ed45..d11d4f0df525e3373233a9f65723d915c5044ed3 100644 (file)
@@ -1,3 +1,14 @@
+2003-12-01  Roger Sayle  <roger@eyesopen.com>
+
+       PR optimization/11634
+       * recog.c (split_insn): Factor test of INSN_P and handling of
+       set_noop_p out of here into the two callers.
+       (split_all_insns): Add INSN_P test and set_noop_p handling here.
+       If deleting a no-op set after reload that has a REG_UNUSED note,
+       mark the basic block as changed and recalculate life information.
+       (split_all_insns_noflow): Add INSN_P test and set_noop_p handling
+       here.
+
 2003-12-01  Roger Sayle  <roger@eyesopen.com>
 
        PR optimization/12322
index f0e75c272f04aeb33a1b785ae8fe087420ab3044..3257fac099db2443ead105c184545072bd6b7c5c 100644 (file)
@@ -2642,61 +2642,42 @@ reg_fits_class_p (rtx operand, enum reg_class class, int offset,
   return 0;
 }
 \f
-/* Split single instruction.  Helper function for split_all_insns.
-   Return last insn in the sequence if successful, or NULL if unsuccessful.  */
+/* Split single instruction.  Helper function for split_all_insns and
+   split_all_insns_noflow.  Return last insn in the sequence if successful,
+   or NULL if unsuccessful.  */
+
 static rtx
 split_insn (rtx insn)
 {
-  rtx set;
-  if (!INSN_P (insn))
-    ;
-  /* Don't split no-op move insns.  These should silently
-     disappear later in final.  Splitting such insns would
-     break the code that handles REG_NO_CONFLICT blocks.  */
+  /* Split insns here to get max fine-grain parallelism.  */
+  rtx first = PREV_INSN (insn);
+  rtx last = try_split (PATTERN (insn), insn, 1);
 
-  else if ((set = single_set (insn)) != NULL && set_noop_p (set))
-    {
-      /* Nops get in the way while scheduling, so delete them
-         now if register allocation has already been done.  It
-         is too risky to try to do this before register
-         allocation, and there are unlikely to be very many
-         nops then anyways.  */
-      if (reload_completed)
-       delete_insn_and_edges (insn);
-    }
-  else
-    {
-      /* Split insns here to get max fine-grain parallelism.  */
-      rtx first = PREV_INSN (insn);
-      rtx last = try_split (PATTERN (insn), insn, 1);
+  if (last == insn)
+    return NULL_RTX;
+
+  /* try_split returns the NOTE that INSN became.  */
+  PUT_CODE (insn, NOTE);
+  NOTE_SOURCE_FILE (insn) = 0;
+  NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
 
-      if (last != insn)
+  /* ??? Coddle to md files that generate subregs in post-reload
+     splitters instead of computing the proper hard register.  */
+  if (reload_completed && first != last)
+    {
+      first = NEXT_INSN (first);
+      for (;;)
        {
-         /* try_split returns the NOTE that INSN became.  */
-         PUT_CODE (insn, NOTE);
-         NOTE_SOURCE_FILE (insn) = 0;
-         NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-
-         /* ??? Coddle to md files that generate subregs in post-
-            reload splitters instead of computing the proper
-            hard register.  */
-         if (reload_completed && first != last)
-           {
-             first = NEXT_INSN (first);
-             while (1)
-               {
-                 if (INSN_P (first))
-                   cleanup_subreg_operands (first);
-                 if (first == last)
-                   break;
-                 first = NEXT_INSN (first);
-               }
-           }
-         return last;
+         if (INSN_P (first))
+           cleanup_subreg_operands (first);
+         if (first == last)
+           break;
+         first = NEXT_INSN (first);
        }
     }
-  return NULL_RTX;
+  return last;
 }
+
 /* Split all insns in the function.  If UPD_LIFE, update life info after.  */
 
 void
@@ -2717,24 +2698,52 @@ split_all_insns (int upd_life)
 
       for (insn = bb->head; !finish ; insn = next)
        {
-         rtx last;
-
          /* Can't use `next_real_insn' because that might go across
             CODE_LABELS and short-out basic blocks.  */
          next = NEXT_INSN (insn);
          finish = (insn == bb->end);
-         last = split_insn (insn);
-         if (last)
+         if (INSN_P (insn))
            {
-             /* The split sequence may include barrier, but the
-                BB boundary we are interested in will be set to previous
-                one.  */
-
-             while (GET_CODE (last) == BARRIER)
-               last = PREV_INSN (last);
-             SET_BIT (blocks, bb->index);
-             changed = true;
-             insn = last;
+             rtx set = single_set (insn);
+
+             /* Don't split no-op move insns.  These should silently
+                disappear later in final.  Splitting such insns would
+                break the code that handles REG_NO_CONFLICT blocks.  */
+             if (set && set_noop_p (set))
+               {
+                 /* Nops get in the way while scheduling, so delete them
+                    now if register allocation has already been done.  It
+                    is too risky to try to do this before register
+                    allocation, and there are unlikely to be very many
+                    nops then anyways.  */
+                 if (reload_completed)
+                   {
+                     /* If the no-op set has a REG_UNUSED note, we need
+                        to update liveness information.  */
+                     if (find_reg_note (insn, REG_UNUSED, NULL_RTX))
+                       {
+                         SET_BIT (blocks, bb->index);
+                         changed = true;
+                       }
+                     /* ??? Is life info affected by deleting edges?  */
+                     delete_insn_and_edges (insn);
+                   }
+               }
+             else
+               {
+                 rtx last = split_insn (insn);
+                 if (last)
+                   {
+                     /* The split sequence may include barrier, but the
+                        BB boundary we are interested in will be set to
+                        previous one.  */
+
+                     while (GET_CODE (last) == BARRIER)
+                       last = PREV_INSN (last);
+                     SET_BIT (blocks, bb->index);
+                     changed = true;
+                   }
+               }
            }
        }
     }
@@ -2771,9 +2780,28 @@ split_all_insns_noflow (void)
   for (insn = get_insns (); insn; insn = next)
     {
       next = NEXT_INSN (insn);
-      split_insn (insn);
+      if (INSN_P (insn))
+       {
+         /* Don't split no-op move insns.  These should silently
+            disappear later in final.  Splitting such insns would
+            break the code that handles REG_NO_CONFLICT blocks.  */
+         rtx set = single_set (insn);
+         if (set && set_noop_p (set))
+           {
+             /* Nops get in the way while scheduling, so delete them
+                now if register allocation has already been done.  It
+                is too risky to try to do this before register
+                allocation, and there are unlikely to be very many
+                nops then anyways.
+
+                ??? Should we use delete_insn when the CFG isn't valid?  */
+             if (reload_completed)
+               delete_insn_and_edges (insn);
+           }
+         else
+           split_insn (insn);
+       }
     }
-  return;
 }
 \f
 #ifdef HAVE_peephole2
index a880222b188a29e9ad7e0044d5b44988e0badee1..d9bc74b3eef10982c5174b5d14b56b2b4f1f3714 100644 (file)
@@ -1,3 +1,8 @@
+2003-12-01  Roger Sayle  <roger@eyesopen.com>
+
+       PR optimization/11634
+       * gcc.dg/20031201-2.c: New test case.
+
 2003-12-01  Zack Weinberg  <zack@codesourcery.com>
 
        PR 11433
diff --git a/gcc/testsuite/gcc.dg/20031201-2.c b/gcc/testsuite/gcc.dg/20031201-2.c
new file mode 100644 (file)
index 0000000..c32b5eb
--- /dev/null
@@ -0,0 +1,41 @@
+/* PR optimization/11634 */
+
+/* The following code used to ICE in verify_local_live_at_start on
+   PA when compiled with -O2.  The cause was that split_all_insns was
+   not updating liveness information when deleting no-op moves that
+   had REG_UNUSED notes.  */
+
+/* { dg-do compile { target hppa*-*-* } } */
+/* { dg-options "-O2" } */
+
+void *f(void *s);
+void H5T_conv_vlen (unsigned long long nelmts, unsigned char *bg_ptr)
+{
+  long long seq_len;
+  unsigned long long bg_seq_len = 0;
+  unsigned src_base_size, dst_base_size;
+  void *tmp_buf = 0;
+  unsigned tmp_buf_size = 0;
+  unsigned long long elmtno;
+  for (elmtno = 0; elmtno < nelmts; elmtno++)
+    {
+      unsigned char *tmp = bg_ptr;
+      bg_seq_len = *tmp;
+      if (bg_seq_len > 0
+          && tmp_buf_size <
+          (unsigned) (bg_seq_len *
+                      (src_base_size > dst_base_size
+                       ? src_base_size
+                      : dst_base_size)))
+       {
+         tmp_buf_size =
+           (unsigned) (bg_seq_len *
+                       (src_base_size > dst_base_size
+                        ? src_base_size
+                        : dst_base_size));
+       }
+      if (bg_seq_len < seq_len)
+       f ((unsigned char *) tmp_buf + dst_base_size * bg_seq_len);
+    }
+}
+