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));
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
}
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;
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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
+