OSDN Git Service

2002-04-23 Roger Sayle <roger@eyesopen.com>
authoraj <aj@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 23 Apr 2002 10:17:37 +0000 (10:17 +0000)
committeraj <aj@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 23 Apr 2002 10:17:37 +0000 (10:17 +0000)
* builtins.c (builtin_memset_gen_str): New function.
(expand_builtin_memset): Optimize the case of constant length, but
unknown value.
testsuite:
* gcc.c-torture/execute/string-opt-17.c: New test case.
* gcc.c-torture/execute/memset-2.c: New test case.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@52662 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/builtins.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/memset-2.c [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/string-opt-17.c [new file with mode: 0644]

index ec7b5e4..571ba03 100644 (file)
@@ -1,3 +1,9 @@
+2002-04-23  Roger Sayle  <roger@eyesopen.com>
+
+       * builtins.c (builtin_memset_gen_str): New function.
+       (expand_builtin_memset): Optimize the case of constant length, but
+       unknown value.
+
 2002-04-23  Aldy Hernandez  <aldyh@redhat.com>
 
         * config/rs6000/altivec.h (vec_step): Remove extraneous
index a1ffe0a..84d47dd 100644 (file)
@@ -126,6 +126,8 @@ static rtx expand_builtin_strncpy   PARAMS ((tree, rtx,
                                                 enum machine_mode));
 static rtx builtin_memset_read_str     PARAMS ((PTR, HOST_WIDE_INT,
                                                 enum machine_mode));
+static rtx builtin_memset_gen_str      PARAMS ((PTR, HOST_WIDE_INT,
+                                                enum machine_mode));
 static rtx expand_builtin_memset       PARAMS ((tree, rtx,
                                                  enum machine_mode));
 static rtx expand_builtin_bzero                PARAMS ((tree));
@@ -2134,6 +2136,34 @@ builtin_memset_read_str (data, offset, mode)
   return c_readstr (p, mode);
 }
 
+/* Callback routine for store_by_pieces.  Return the RTL of a register
+   containing GET_MODE_SIZE (MODE) consecutive copies of the unsigned
+   char value given in the RTL register data.  For example, if mode is
+   4 bytes wide, return the RTL for 0x01010101*data.  */
+
+static rtx
+builtin_memset_gen_str (data, offset, mode)
+     PTR data;
+     HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
+     enum machine_mode mode;
+{
+  rtx target, coeff;
+  size_t size;
+  char *p;
+
+  size = GET_MODE_SIZE (mode);
+  if (size==1)
+    return (rtx)data;
+
+  p = alloca (size);
+  memset (p, 1, size);
+  coeff = c_readstr (p, mode);
+
+  target = convert_to_mode (mode, (rtx)data, 1);
+  target = expand_mult (mode, target, coeff, NULL_RTX, 1);
+  return force_reg (mode, target);
+}
+
 /* Expand expression EXP, which is a call to the memset builtin.  Return 0
    if we failed the caller should emit a normal call, otherwise try to get
    the result in TARGET, if convenient (and in mode MODE if that's
@@ -2175,7 +2205,34 @@ expand_builtin_memset (exp, target, mode)
         }
 
       if (TREE_CODE (val) != INTEGER_CST)
-       return 0;
+        {
+          rtx val_rtx;
+
+          if (!host_integerp (len, 1))
+            return 0;
+
+          if (optimize_size && tree_low_cst (len, 1) > 1)
+            return 0;
+
+          /* Assume that we can memset by pieces if we can store the
+           * the coefficients by pieces (in the required modes).
+           * We can't pass builtin_memset_gen_str as that emits RTL.  */
+          c = 1;
+         if (!can_store_by_pieces (tree_low_cst (len, 1),
+                                   builtin_memset_read_str,
+                                    (PTR) &c, dest_align))
+           return 0;
+
+          val = fold (build1 (CONVERT_EXPR, unsigned_char_type_node, val));
+          val_rtx = expand_expr (val, NULL_RTX, VOIDmode, 0);
+          val_rtx = force_reg (TYPE_MODE (unsigned_char_type_node),
+                               val_rtx);
+         dest_mem = get_memory_rtx (dest);
+         store_by_pieces (dest_mem, tree_low_cst (len, 1),
+                          builtin_memset_gen_str,
+                          (PTR)val_rtx, dest_align);
+         return force_operand (XEXP (dest_mem, 0), NULL_RTX);
+        }
 
       if (target_char_cast (val, &c))
        return 0;
index 3c4635a..c1641dd 100644 (file)
@@ -1,3 +1,8 @@
+2002-04-23  Roger Sayle  <roger@eyesopen.com>
+
+       * gcc.c-torture/execute/string-opt-17.c: New test case.
+       * gcc.c-torture/execute/memset-2.c: New test case.
+
 2002-04-23  Mark Mitchell  <mark@codesourcery.com>
 
        PR c++/6256:
        * g++.dg/opt/const1.C: New test.
 
 2002-04-10  Lars Brinkhoff  <lars@nocrew.org>
+
        * gcc.c-torture/execute/20020406-1.c: Declare malloc.
 
 2002-04-10  Nathan Sidwell  <nathan@codesourcery.com>
 2002-03-27  Mark Mitchell  <mark@codesourcery.com>
 
        * g++.dg/init/new2.C: New test.
-       
+
 2002-03-26  Richard Henderson  <rth@redhat.com>
 
        * gcc.dg/pragma-re-2.c: Avoid empty source file warning.
diff --git a/gcc/testsuite/gcc.c-torture/execute/memset-2.c b/gcc/testsuite/gcc.c-torture/execute/memset-2.c
new file mode 100644 (file)
index 0000000..07c3db3
--- /dev/null
@@ -0,0 +1,334 @@
+/* Copyright (C) 2002  Free Software Foundation.
+
+   Test memset with various combinations of pointer alignments and constant
+   lengths to make sure any optimizations in the compiler are correct.
+
+   Written by Roger Sayle, April 22, 2002.  */
+
+#ifndef MAX_OFFSET
+#define MAX_OFFSET (sizeof (long long))
+#endif
+
+#ifndef MAX_COPY
+#define MAX_COPY 15
+#endif
+
+#ifndef MAX_EXTRA
+#define MAX_EXTRA (sizeof (long long))
+#endif
+
+#define MAX_LENGTH (MAX_OFFSET + MAX_COPY + MAX_EXTRA)
+
+static union {
+  char buf[MAX_LENGTH];
+  long long align_int;
+  long double align_fp;
+} u;
+
+char A = 'A';
+
+void reset ()
+{
+  int i;
+
+  for (i = 0; i < MAX_LENGTH; i++)
+    u.buf[i] = 'a';
+}
+
+void check (int off, int len, int ch)
+{
+  char *q;
+  int i;
+
+  q = u.buf;
+  for (i = 0; i < off; i++, q++)
+    if (*q != 'a')
+      abort ();
+
+  for (i = 0; i < len; i++, q++)
+    if (*q != ch)
+      abort ();
+
+  for (i = 0; i < MAX_EXTRA; i++, q++)
+    if (*q != 'a')
+      abort ();
+}
+
+int main ()
+{
+  int off;
+  char *p;
+
+  /* len == 1 */
+  for (off = 0; off < MAX_OFFSET; off++)
+    {
+      reset ();
+
+      p = memset (u.buf + off, '\0', 1);
+      if (p != u.buf + off) abort ();
+      check (off, 1, '\0');
+
+      p = memset (u.buf + off, A, 1);
+      if (p != u.buf + off) abort ();
+      check (off, 1, 'A');
+
+      p = memset (u.buf + off, 'B', 1);
+      if (p != u.buf + off) abort ();
+      check (off, 1, 'B');
+    }
+
+  /* len == 2 */
+  for (off = 0; off < MAX_OFFSET; off++)
+    {
+      reset ();
+
+      p = memset (u.buf + off, '\0', 2);
+      if (p != u.buf + off) abort ();
+      check (off, 2, '\0');
+
+      p = memset (u.buf + off, A, 2);
+      if (p != u.buf + off) abort ();
+      check (off, 2, 'A');
+
+      p = memset (u.buf + off, 'B', 2);
+      if (p != u.buf + off) abort ();
+      check (off, 2, 'B');
+    }
+
+  /* len == 3 */
+  for (off = 0; off < MAX_OFFSET; off++)
+    {
+      reset ();
+
+      p = memset (u.buf + off, '\0', 3);
+      if (p != u.buf + off) abort ();
+      check (off, 3, '\0');
+
+      p = memset (u.buf + off, A, 3);
+      if (p != u.buf + off) abort ();
+      check (off, 3, 'A');
+
+      p = memset (u.buf + off, 'B', 3);
+      if (p != u.buf + off) abort ();
+      check (off, 3, 'B');
+    }
+
+  /* len == 4 */
+  for (off = 0; off < MAX_OFFSET; off++)
+    {
+      reset ();
+
+      p = memset (u.buf + off, '\0', 4);
+      if (p != u.buf + off) abort ();
+      check (off, 4, '\0');
+
+      p = memset (u.buf + off, A, 4);
+      if (p != u.buf + off) abort ();
+      check (off, 4, 'A');
+
+      p = memset (u.buf + off, 'B', 4);
+      if (p != u.buf + off) abort ();
+      check (off, 4, 'B');
+    }
+
+  /* len == 5 */
+  for (off = 0; off < MAX_OFFSET; off++)
+    {
+      reset ();
+
+      p = memset (u.buf + off, '\0', 5);
+      if (p != u.buf + off) abort ();
+      check (off, 5, '\0');
+
+      p = memset (u.buf + off, A, 5);
+      if (p != u.buf + off) abort ();
+      check (off, 5, 'A');
+
+      p = memset (u.buf + off, 'B', 5);
+      if (p != u.buf + off) abort ();
+      check (off, 5, 'B');
+    }
+
+  /* len == 6 */
+  for (off = 0; off < MAX_OFFSET; off++)
+    {
+      reset ();
+
+      p = memset (u.buf + off, '\0', 6);
+      if (p != u.buf + off) abort ();
+      check (off, 6, '\0');
+
+      p = memset (u.buf + off, A, 6);
+      if (p != u.buf + off) abort ();
+      check (off, 6, 'A');
+
+      p = memset (u.buf + off, 'B', 6);
+      if (p != u.buf + off) abort ();
+      check (off, 6, 'B');
+    }
+
+  /* len == 7 */
+  for (off = 0; off < MAX_OFFSET; off++)
+    {
+      reset ();
+
+      p = memset (u.buf + off, '\0', 7);
+      if (p != u.buf + off) abort ();
+      check (off, 7, '\0');
+
+      p = memset (u.buf + off, A, 7);
+      if (p != u.buf + off) abort ();
+      check (off, 7, 'A');
+
+      p = memset (u.buf + off, 'B', 7);
+      if (p != u.buf + off) abort ();
+      check (off, 7, 'B');
+    }
+
+  /* len == 8 */
+  for (off = 0; off < MAX_OFFSET; off++)
+    {
+      reset ();
+
+      p = memset (u.buf + off, '\0', 8);
+      if (p != u.buf + off) abort ();
+      check (off, 8, '\0');
+
+      p = memset (u.buf + off, A, 8);
+      if (p != u.buf + off) abort ();
+      check (off, 8, 'A');
+
+      p = memset (u.buf + off, 'B', 8);
+      if (p != u.buf + off) abort ();
+      check (off, 8, 'B');
+    }
+
+  /* len == 9 */
+  for (off = 0; off < MAX_OFFSET; off++)
+    {
+      reset ();
+
+      p = memset (u.buf + off, '\0', 9);
+      if (p != u.buf + off) abort ();
+      check (off, 9, '\0');
+
+      p = memset (u.buf + off, A, 9);
+      if (p != u.buf + off) abort ();
+      check (off, 9, 'A');
+
+      p = memset (u.buf + off, 'B', 9);
+      if (p != u.buf + off) abort ();
+      check (off, 9, 'B');
+    }
+
+  /* len == 10 */
+  for (off = 0; off < MAX_OFFSET; off++)
+    {
+      reset ();
+
+      p = memset (u.buf + off, '\0', 10);
+      if (p != u.buf + off) abort ();
+      check (off, 10, '\0');
+
+      p = memset (u.buf + off, A, 10);
+      if (p != u.buf + off) abort ();
+      check (off, 10, 'A');
+
+      p = memset (u.buf + off, 'B', 10);
+      if (p != u.buf + off) abort ();
+      check (off, 10, 'B');
+    }
+
+  /* len == 11 */
+  for (off = 0; off < MAX_OFFSET; off++)
+    {
+      reset ();
+
+      p = memset (u.buf + off, '\0', 11);
+      if (p != u.buf + off) abort ();
+      check (off, 11, '\0');
+
+      p = memset (u.buf + off, A, 11);
+      if (p != u.buf + off) abort ();
+      check (off, 11, 'A');
+
+      p = memset (u.buf + off, 'B', 11);
+      if (p != u.buf + off) abort ();
+      check (off, 11, 'B');
+    }
+
+  /* len == 12 */
+  for (off = 0; off < MAX_OFFSET; off++)
+    {
+      reset ();
+
+      p = memset (u.buf + off, '\0', 12);
+      if (p != u.buf + off) abort ();
+      check (off, 12, '\0');
+
+      p = memset (u.buf + off, A, 12);
+      if (p != u.buf + off) abort ();
+      check (off, 12, 'A');
+
+      p = memset (u.buf + off, 'B', 12);
+      if (p != u.buf + off) abort ();
+      check (off, 12, 'B');
+    }
+
+  /* len == 13 */
+  for (off = 0; off < MAX_OFFSET; off++)
+    {
+      reset ();
+
+      p = memset (u.buf + off, '\0', 13);
+      if (p != u.buf + off) abort ();
+      check (off, 13, '\0');
+
+      p = memset (u.buf + off, A, 13);
+      if (p != u.buf + off) abort ();
+      check (off, 13, 'A');
+
+      p = memset (u.buf + off, 'B', 13);
+      if (p != u.buf + off) abort ();
+      check (off, 13, 'B');
+    }
+
+  /* len == 14 */
+  for (off = 0; off < MAX_OFFSET; off++)
+    {
+      reset ();
+
+      p = memset (u.buf + off, '\0', 14);
+      if (p != u.buf + off) abort ();
+      check (off, 14, '\0');
+
+      p = memset (u.buf + off, A, 14);
+      if (p != u.buf + off) abort ();
+      check (off, 14, 'A');
+
+      p = memset (u.buf + off, 'B', 14);
+      if (p != u.buf + off) abort ();
+      check (off, 14, 'B');
+    }
+
+  /* len == 15 */
+  for (off = 0; off < MAX_OFFSET; off++)
+    {
+      reset ();
+
+      p = memset (u.buf + off, '\0', 15);
+      if (p != u.buf + off) abort ();
+      check (off, 15, '\0');
+
+      p = memset (u.buf + off, A, 15);
+      if (p != u.buf + off) abort ();
+      check (off, 15, 'A');
+
+      p = memset (u.buf + off, 'B', 15);
+      if (p != u.buf + off) abort ();
+      check (off, 15, 'B');
+    }
+
+  exit (0);
+}
+
diff --git a/gcc/testsuite/gcc.c-torture/execute/string-opt-17.c b/gcc/testsuite/gcc.c-torture/execute/string-opt-17.c
new file mode 100644 (file)
index 0000000..47fe42d
--- /dev/null
@@ -0,0 +1,50 @@
+/* Copyright (C) 2002  Free Software Foundation.
+
+   Ensure that builtin memset operations for constant length and
+   non-constant assigned value don't cause compiler problems.
+
+   Written by Roger Sayle, 21 April 2002.  */
+
+extern void abort (void);
+typedef __SIZE_TYPE__ size_t;
+extern void *memset (void *, int, size_t);
+
+char buffer[32];
+
+int
+main (int argc)
+{
+  memset (buffer, argc, 0);
+  memset (buffer, argc, 1);
+  memset (buffer, argc, 2);
+  memset (buffer, argc, 3);
+  memset (buffer, argc, 4);
+  memset (buffer, argc, 5);
+  memset (buffer, argc, 6);
+  memset (buffer, argc, 7);
+  memset (buffer, argc, 8);
+  memset (buffer, argc, 9);
+  memset (buffer, argc, 10);
+  memset (buffer, argc, 11);
+  memset (buffer, argc, 12);
+  memset (buffer, argc, 13);
+  memset (buffer, argc, 14);
+  memset (buffer, argc, 15);
+  memset (buffer, argc, 16);
+  memset (buffer, argc, 17);
+
+  return 0;
+}
+
+#ifdef __OPTIMIZE__
+/* When optimizing, most of the above cases should be transformed into
+   something else.  So any remaining calls to the original function
+   for short lengths should abort.  */
+static void *
+memset (void *dst, int c, size_t len)
+{
+  if (len < 2)
+    abort ();
+}
+#endif
+