This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Fix PR rtl-optimization/24883


PR rtl-optimization/24883 provides a test case which fails during
compilation on s390-linux.  The problem is that combine.c loses a
REG_DEAD note.  It loses it when it combines these insns

(insn 82 80 85 15 (parallel [
            (set (subreg:SI (reg/v:QI 46 [ ci.52 ]) 0)
                (xor:SI (subreg:SI (reg/v:QI 49 [ cj ]) 0)
                    (subreg:SI (reg/v:QI 50 [ ci ]) 0)))
            (clobber (reg:CC 33 %cc))
        ]) 267 {*xorsi3} (nil)
    (expr_list:REG_DEAD (reg/v:QI 49 [ cj ])
        (expr_list:REG_UNUSED (reg:CC 33 %cc)
            (nil))))

(insn 85 82 87 15 (set (subreg:SI (reg:QI 69 [ ci ]) 0)
        (subreg:SI (reg/v:QI 50 [ ci ]) 0)) 52 {*movsi_esa} (nil)
    (expr_list:REG_DEAD (reg/v:QI 50 [ ci ])
        (nil)))

(insn 87 85 89 15 (parallel [
            (set (subreg:SI (reg/v:QI 50 [ ci ]) 0)
                (xor:SI (subreg:SI (reg/v:QI 46 [ ci.52 ]) 0)
                    (subreg:SI (reg:QI 69 [ ci ]) 0)))
            (clobber (reg:CC 33 %cc))
        ]) 267 {*xorsi3} (insn_list:REG_DEP_TRUE 82 (insn_list:REG_DEP_TRUE 85 (nil)))
    (expr_list:REG_DEAD (reg/v:QI 46 [ ci.52 ])
        (expr_list:REG_DEAD (reg:QI 69 [ ci ])
            (expr_list:REG_UNUSED (reg:CC 33 %cc)
                (nil)))))

into this:

(note 82 80 85 15 NOTE_INSN_DELETED)

(note 85 82 87 15 NOTE_INSN_DELETED)

(insn 87 85 89 15 (set (subreg:SI (reg/v:QI 50 [ ci ]) 0)
        (subreg:SI (reg/v:QI 49 [ cj ]) 0)) 52 {*movsi_esa} (nil)
    (expr_list:REG_DEAD (reg/v:QI 49 [ cj ])
        (nil)))

This is turning
    ci ^= cj;
    cj ^= ci;
    ci ^= cj;
(where cj is dead afterward) into
    ci = cj;
The ^= operations are basically an overly-clever swap, and gcc is
unpacking that.

The original insn 85 has a REG_DEAD note for register 50, and the
original insn 87 sets register 50.  The REG_DEAD note is lost because
an intermediate stage during combine produced an insn which sets
register 50 based on register 50.  That insn naturally does not have a
REG_DEAD note for register 50, because it is both used and set.  The
combine pass then merges that insn, and the merge eliminates the use
of register 50.  At that point, the original REG_DEAD note has been
lost.

There is code in combine.c to handle this case--the case of an insn
which both uses and sets a register being turned into an insn which
only sets the register.  However, the code did not trigger here
because the register is referred to as (subreg:SI (reg/v:QI 50) 0).

This problem is a latent bug which was exposed by this patch:

2005-09-06  Saurabh Verma  <saurabh.verma@codito.com>

	* simplify-rtx.c (simplify_binary_operation_1): Correct the
	condition for detecting cases like (a&a) and (a^a).

My patch, below, simply adds detection of paradoxical subregs when
checking for an insn that both uses and sets a register.

Richard Guenther bootstrapped and tested the patch on s390-linux-gnu
(thanks!).  I bootstrapped it in i686-pc-linux-gnu.

Committing to mainline and 4.1 branch.  Not committing to 3.4 or 4.0
branch because I don't have a test case--the latent bug is an ICE, not
a wrong-code, and it doesn't seem useful to patch a release branch for
a hypothetical ICE.

Ian


gcc/ChangeLog
2005-11-20  Ian Lance Taylor  <ian@airs.com>

	PR rtl-optimization/24883
	* combine.c (combinable_i3pat): When checking whether the
	destination of i3 is used in i3, consider paradoxical subregs.

gcc/testsuite/ChangeLog:
2005-11-20  Ian Lance Taylor  <ian@airs.com>

	PR rtl-optimization/24883
	* gcc.c-torture/compile/pr24883.c: New test.


Index: combine.c
===================================================================
--- combine.c	(revision 107262)
+++ combine.c	(working copy)
@@ -1423,6 +1423,7 @@ combinable_i3pat (rtx i3, rtx *loc, rtx 
       rtx dest = SET_DEST (set);
       rtx src = SET_SRC (set);
       rtx inner_dest = dest;
+      rtx subdest;
 
       while (GET_CODE (inner_dest) == STRICT_LOW_PART
 	     || GET_CODE (inner_dest) == SUBREG
@@ -1457,27 +1458,35 @@ combinable_i3pat (rtx i3, rtx *loc, rtx 
 	  || (i1_not_in_src && reg_overlap_mentioned_p (i1dest, src)))
 	return 0;
 
-      /* If DEST is used in I3, it is being killed in this insn,
-	 so record that for later.
+      /* If DEST is used in I3, it is being killed in this insn, so
+	 record that for later.  We have to consider paradoxical
+	 subregs here, since they kill the whole register, but we
+	 ignore partial subregs, STRICT_LOW_PART, etc.
 	 Never add REG_DEAD notes for the FRAME_POINTER_REGNUM or the
 	 STACK_POINTER_REGNUM, since these are always considered to be
 	 live.  Similarly for ARG_POINTER_REGNUM if it is fixed.  */
-      if (pi3dest_killed && REG_P (dest)
-	  && reg_referenced_p (dest, PATTERN (i3))
-	  && REGNO (dest) != FRAME_POINTER_REGNUM
+      subdest = dest;
+      if (GET_CODE (subdest) == SUBREG
+	  && (GET_MODE_SIZE (GET_MODE (subdest))
+	      >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (subdest)))))
+	subdest = SUBREG_REG (subdest);
+      if (pi3dest_killed
+	  && REG_P (subdest)
+	  && reg_referenced_p (subdest, PATTERN (i3))
+	  && REGNO (subdest) != FRAME_POINTER_REGNUM
 #if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
-	  && REGNO (dest) != HARD_FRAME_POINTER_REGNUM
+	  && REGNO (subdest) != HARD_FRAME_POINTER_REGNUM
 #endif
 #if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
-	  && (REGNO (dest) != ARG_POINTER_REGNUM
-	      || ! fixed_regs [REGNO (dest)])
+	  && (REGNO (subdest) != ARG_POINTER_REGNUM
+	      || ! fixed_regs [REGNO (subdest)])
 #endif
-	  && REGNO (dest) != STACK_POINTER_REGNUM)
+	  && REGNO (subdest) != STACK_POINTER_REGNUM)
 	{
 	  if (*pi3dest_killed)
 	    return 0;
 
-	  *pi3dest_killed = dest;
+	  *pi3dest_killed = subdest;
 	}
     }
 
Index: testsuite/gcc.c-torture/compile/pr24883.c
===================================================================
--- testsuite/gcc.c-torture/compile/pr24883.c	(revision 0)
+++ testsuite/gcc.c-torture/compile/pr24883.c	(revision 0)
@@ -0,0 +1,21 @@
+typedef struct _rec_stl rec_stl;
+struct _rec_stl {
+   unsigned char **strs;
+};
+orec_str_list(int count) {
+   rec_stl *stl;
+   int i, j;
+   int li, lj;
+   unsigned char ci, cj;
+   for (i = 0; i < count; i++) {
+      for (j = i + 1; j < count; j++) {
+         cj = lj > 2 ? stl->strs[j][0] : (long)stl->strs[j] & 0xff;
+         if ((count >= 16 && cj < ci) || (cj == ci && lj > li)) {
+            stl->strs[j] = stl->strs[i];
+            ci ^= cj;
+            cj ^= ci;
+            ci ^= cj;
+         }
+      }
+   }
+}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]