Commit 1a887f86 by Roger Sayle Committed by Andreas Jaeger

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
parent 77adef84
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> 2002-04-23 Aldy Hernandez <aldyh@redhat.com>
* config/rs6000/altivec.h (vec_step): Remove extraneous * config/rs6000/altivec.h (vec_step): Remove extraneous
......
...@@ -126,6 +126,8 @@ static rtx expand_builtin_strncpy PARAMS ((tree, rtx, ...@@ -126,6 +126,8 @@ static rtx expand_builtin_strncpy PARAMS ((tree, rtx,
enum machine_mode)); enum machine_mode));
static rtx builtin_memset_read_str PARAMS ((PTR, HOST_WIDE_INT, static rtx builtin_memset_read_str PARAMS ((PTR, HOST_WIDE_INT,
enum machine_mode)); 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, static rtx expand_builtin_memset PARAMS ((tree, rtx,
enum machine_mode)); enum machine_mode));
static rtx expand_builtin_bzero PARAMS ((tree)); static rtx expand_builtin_bzero PARAMS ((tree));
...@@ -2134,6 +2136,34 @@ builtin_memset_read_str (data, offset, mode) ...@@ -2134,6 +2136,34 @@ builtin_memset_read_str (data, offset, mode)
return c_readstr (p, 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 /* 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 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 the result in TARGET, if convenient (and in mode MODE if that's
...@@ -2175,7 +2205,34 @@ expand_builtin_memset (exp, target, mode) ...@@ -2175,7 +2205,34 @@ expand_builtin_memset (exp, target, mode)
} }
if (TREE_CODE (val) != INTEGER_CST) 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)) if (target_char_cast (val, &c))
return 0; return 0;
......
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> 2002-04-23 Mark Mitchell <mark@codesourcery.com>
PR c++/6256: PR c++/6256:
...@@ -167,7 +172,7 @@ ...@@ -167,7 +172,7 @@
* g++.dg/opt/const1.C: New test. * g++.dg/opt/const1.C: New test.
2002-04-10 Lars Brinkhoff <lars@nocrew.org> 2002-04-10 Lars Brinkhoff <lars@nocrew.org>
* gcc.c-torture/execute/20020406-1.c: Declare malloc. * gcc.c-torture/execute/20020406-1.c: Declare malloc.
2002-04-10 Nathan Sidwell <nathan@codesourcery.com> 2002-04-10 Nathan Sidwell <nathan@codesourcery.com>
...@@ -330,7 +335,7 @@ ...@@ -330,7 +335,7 @@
2002-03-27 Mark Mitchell <mark@codesourcery.com> 2002-03-27 Mark Mitchell <mark@codesourcery.com>
* g++.dg/init/new2.C: New test. * g++.dg/init/new2.C: New test.
2002-03-26 Richard Henderson <rth@redhat.com> 2002-03-26 Richard Henderson <rth@redhat.com>
* gcc.dg/pragma-re-2.c: Avoid empty source file warning. * gcc.dg/pragma-re-2.c: Avoid empty source file warning.
......
/* 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);
}
/* 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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment