summaryrefslogtreecommitdiffstats
path: root/newlib/libc/machine/mips/memset.c
diff options
context:
space:
mode:
Diffstat (limited to 'newlib/libc/machine/mips/memset.c')
-rw-r--r--newlib/libc/machine/mips/memset.c142
1 files changed, 142 insertions, 0 deletions
diff --git a/newlib/libc/machine/mips/memset.c b/newlib/libc/machine/mips/memset.c
new file mode 100644
index 000000000..786ba7971
--- /dev/null
+++ b/newlib/libc/machine/mips/memset.c
@@ -0,0 +1,142 @@
+/*
+FUNCTION
+ <<memset>>---set an area of memory, optimized for the MIPS processors
+
+INDEX
+ memset
+
+ANSI_SYNOPSIS
+ #include <string.h>
+ void *memset(const void *<[dst]>, int <[c]>, size_t <[length]>);
+
+TRAD_SYNOPSIS
+ #include <string.h>
+ void *memset(<[dst]>, <[c]>, <[length]>)
+ void *<[dst]>;
+ int <[c]>;
+ size_t <[length]>;
+
+DESCRIPTION
+ This function converts the argument <[c]> into an unsigned
+ char and fills the first <[length]> characters of the array
+ pointed to by <[dst]> to the value.
+
+RETURNS
+ <<memset>> returns the value of <[m]>.
+
+PORTABILITY
+<<memset>> is ANSI C.
+
+ <<memset>> requires no supporting OS subroutines.
+
+QUICKREF
+ memset ansi pure
+*/
+
+#include <string.h>
+
+#ifdef __mips64
+#define wordtype long long
+#else
+#define wordtype long
+#endif
+
+#define LBLOCKSIZE (sizeof(wordtype))
+#define UNALIGNED(X) ((long)(X) & (LBLOCKSIZE - 1))
+#define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE * 4)
+
+_PTR
+_DEFUN (memset, (m, c, n),
+ _PTR m _AND
+ int c _AND
+ size_t n)
+{
+#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) || defined(__mips16)
+ char *s = (char *) m;
+
+ while (n-- != 0)
+ {
+ *s++ = (char) c;
+ }
+
+ return m;
+#else
+ char *s = (char *) m;
+ int i;
+ unsigned wordtype buffer;
+ unsigned wordtype *aligned_addr;
+ unsigned short *short_addr;
+ size_t iter;
+
+ if (!TOO_SMALL (n))
+ {
+ int unaligned = UNALIGNED (s);
+
+ /* We know that N is >= LBLOCKSIZE so we can just word
+ align the S without having to check the length. */
+
+ if (unaligned)
+ {
+ while (unaligned++ < LBLOCKSIZE)
+ *s++ = (char)c, n--;
+ }
+
+ /* S is now word-aligned so we can process the remainder
+ in word sized chunks except for a few (< LBLOCKSIZE)
+ bytes which might be left over at the end. */
+
+ aligned_addr = (unsigned wordtype *)s;
+
+ /* Store C into each char sized location in BUFFER so that
+ we can set large blocks quickly. */
+ c &= 0xff;
+ buffer = c;
+ if (buffer != 0)
+ {
+ if (LBLOCKSIZE == 4)
+ {
+ buffer |= (buffer << 8);
+ buffer |= (buffer << 16);
+ }
+ else if (LBLOCKSIZE == 8)
+ {
+ buffer |= (buffer << 8);
+ buffer |= (buffer << 16);
+ buffer |= ((buffer << 31) << 1);
+ }
+ else
+ {
+ for (i = 1; i < LBLOCKSIZE; i++)
+ buffer = (buffer << 8) | c;
+ }
+ }
+
+ iter = n / (2*LBLOCKSIZE);
+ n = n % (2*LBLOCKSIZE);
+ while (iter > 0)
+ {
+ aligned_addr[0] = buffer;
+ aligned_addr[1] = buffer;
+ aligned_addr += 2;
+ iter--;
+ }
+
+ if (n >= LBLOCKSIZE)
+ {
+ *aligned_addr++ = buffer;
+ n -= LBLOCKSIZE;
+ }
+
+ /* Pick up the remainder with a bytewise loop. */
+ s = (char*)aligned_addr;
+ }
+
+ while (n > 0)
+ {
+ *s++ = (char)c;
+ n--;
+ }
+
+ return m;
+#endif /* not PREFER_SIZE_OVER_SPEED */
+}