aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Sayle <roger@eyesopen.com>2002-04-23 10:17:37 +0000
committerAndreas Jaeger <aj@gcc.gnu.org>2002-04-23 12:17:37 +0200
commit1a887f860a2905e95ab853fb1f8adef14515d74e (patch)
tree5c7e4a7521145a5c59ecb25c52fa10c1cb4acc39
parent77adef8498fb09947e889abbacb1d2bd8ece0929 (diff)
downloadgcc-1a887f860a2905e95ab853fb1f8adef14515d74e.zip
gcc-1a887f860a2905e95ab853fb1f8adef14515d74e.tar.gz
gcc-1a887f860a2905e95ab853fb1f8adef14515d74e.tar.bz2
builtins.c (builtin_memset_gen_str): New function.
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. testsuite: * gcc.c-torture/execute/string-opt-17.c: New test case. * gcc.c-torture/execute/memset-2.c: New test case. From-SVN: r52662
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/builtins.c59
-rw-r--r--gcc/testsuite/ChangeLog9
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/memset-2.c334
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/string-opt-17.c50
5 files changed, 455 insertions, 3 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index ec7b5e4..571ba03 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/builtins.c b/gcc/builtins.c
index a1ffe0a..84d47dd 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -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;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 3c4635a..c1641dd 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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:
@@ -167,7 +172,7 @@
* 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>
@@ -330,7 +335,7 @@
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
index 0000000..07c3db3
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/memset-2.c
@@ -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
index 0000000..47fe42d
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/string-opt-17.c
@@ -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
+