diff options
author | Roger Sayle <roger@eyesopen.com> | 2002-04-23 10:17:37 +0000 |
---|---|---|
committer | Andreas Jaeger <aj@gcc.gnu.org> | 2002-04-23 12:17:37 +0200 |
commit | 1a887f860a2905e95ab853fb1f8adef14515d74e (patch) | |
tree | 5c7e4a7521145a5c59ecb25c52fa10c1cb4acc39 /gcc | |
parent | 77adef8498fb09947e889abbacb1d2bd8ece0929 (diff) | |
download | gcc-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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/builtins.c | 59 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/memset-2.c | 334 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/string-opt-17.c | 50 |
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 + |