]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
loop.c (maybe_eliminate_biv_1): Avoid signed/unsigned comparison confusion when setti...
authorMark Mitchell <mark@markmitchell.com>
Sat, 18 Jul 1998 15:21:13 +0000 (15:21 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Sat, 18 Jul 1998 15:21:13 +0000 (15:21 +0000)
* loop.c (maybe_eliminate_biv_1): Avoid signed/unsigned comparison
confusion when setting cc0.

From-SVN: r21273

gcc/ChangeLog
gcc/loop.c
gcc/testsuite/gcc.c-torture/execute/loop-2g.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/loop-2g.x [new file with mode: 0644]

index 360fa628dbd02ca7d20d175e117c29a464c048c7..ebbb1bdd39f670cc73ae78de75e3a7df7de974a2 100644 (file)
@@ -1,3 +1,8 @@
+Sat Jul 18 15:20:19 1998  Mark Mitchell  <mark@markmitchell.com>
+
+       * loop.c (maybe_eliminate_biv_1): Avoid signed/unsigned comparison
+       confusion when setting cc0.
+
 Fri Jul 17 03:26:12 1998  Rihcard Earnshaw (rearnsha@arm.com)
 
        * tree.c (valid_machine_attribute): Only create a new type variant if
index 0171741e22b7ac07ea4b8ec40ad893f6a479ea70..7e2c4d1d220bce7f3f99b52a1210901cc2dabc1d 100644 (file)
@@ -6550,7 +6550,42 @@ maybe_eliminate_biv_1 (x, insn, bl, eliminate_p, where)
          return 1;
 
 #ifdef HAVE_cc0
-      if (SET_DEST (x) == cc0_rtx && SET_SRC (x) == reg)
+      /* The idea here is to replace the SET of cc0 by a REG with
+        a comparison involving related induction variables.
+        Unfortunately, however, such a replacement does not work
+        correctly if the REG is being used as signed and the
+        replacement value is unsigned, or vice versa.  For
+        example, in:
+
+           for (int i = n; i >= 0; --i)
+             s[i] = 3;
+
+        `s' is an address (an unsigned quantity), while `i' is a
+        signed quantity.  The exit test for the loop might look
+        something like:
+
+           (SET cc0 i)
+           (JUMP (SET (PC) (IF_THEN_ELSE (LT (CC0) (CONST_INT 0))
+                            (LABEL_REF L) (PC))))
+
+        If we replace the SET of cc0 with a comparison of the
+        induction variable for `s + i' and the original value of `s',
+        however, we should be change the comparison in the
+        IF_THEN_ELSE to be unsigned.  Otherwise, an array the spans
+        the boundary between "negative" and "positive" addresses will
+        confuse us.
+
+        There are related problems with overflow.  If an induction
+        variable "wraps around" but the original value doest not, we
+        can get confused when doing the comparison.
+
+        Pointers can't wrap around, or overflow, in a conformant
+        program.  Therefore, it's safe to do these optimizations if
+        both the original REG and the values in the replacement are
+        pointers.  For now, though, we just disable these
+        optimizations.  */
+
+      if (0 && SET_DEST (x) == cc0_rtx && SET_SRC (x) == reg)
        {
          /* Can replace with any giv that was reduced and
             that has (MULT_VAL != 0) and (ADD_VAL == 0).
diff --git a/gcc/testsuite/gcc.c-torture/execute/loop-2g.c b/gcc/testsuite/gcc.c-torture/execute/loop-2g.c
new file mode 100644 (file)
index 0000000..8792dbf
--- /dev/null
@@ -0,0 +1,63 @@
+#include <limits.h>
+
+#ifdef __unix__ /* ??? Is that good enough? */
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifndef MAP_ANON
+#ifdef MAP_ANONYMOUS
+#define MAP_ANON MAP_ANONYMOUS
+#else
+#define MAP_ANON MAP_FILE
+#endif
+#endif
+#ifndef MAP_FILE
+#define MAP_FILE 0
+#endif
+#ifndef MAP_FIXED
+#define MAP_FIXED 0
+#endif
+#endif
+
+#define MAP_START (void *)0x7fff8000
+#define MAP_LEN 0x10000
+
+#define OFFSET (MAP_LEN/2 - 2 * sizeof (char));
+
+f (int s, char *p)
+{
+  int i;
+  for (i = s; &p[i] < &p[40] && i >= 0; i++)
+    {
+      p[i] = -2;
+    }
+}
+
+main ()
+{
+#ifdef MAP_ANON
+  char *p;
+  int dev_zero;
+
+  dev_zero = open ("/dev/zero", O_RDONLY);
+  /* -1 is OK when we have MAP_ANON; else mmap will flag an error.  */
+  if (INT_MAX != 0x7fffffffL || sizeof (char *) != sizeof (int))
+    exit (0);
+  p = mmap (MAP_START, MAP_LEN, PROT_READ|PROT_WRITE,
+           MAP_ANON|MAP_FIXED|MAP_PRIVATE, dev_zero, 0);
+  if (p != (char *)-1)
+    {
+      p += OFFSET;
+      p[39] = 0;
+      f (0, p);
+      if (p[39] != (char)-2)
+       abort ();
+      p[39] = 0;
+      f (-1, p);
+      if (p[39] != 0)
+       abort ();
+    }
+#endif
+  exit (0);
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/loop-2g.x b/gcc/testsuite/gcc.c-torture/execute/loop-2g.x
new file mode 100644 (file)
index 0000000..e68b8fb
--- /dev/null
@@ -0,0 +1,9 @@
+# This doesn't work on m68k-motorola-sysv
+# It also doesn't work on m88k-motorola-sysv3
+
+global target_triplet
+if { [istarget "m68k-motorola-sysv"] || [istarget "m88k-motorola-sysv3"] } {
+      set torture_compile_xfail "$target_triplet"
+}
+
+return 0