1 /*
2 Copyright (c) 1994 Cygnus Support.
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms are permitted
6 provided that the above copyright notice and this paragraph are
7 duplicated in all such forms and that any documentation,
8 and/or other materials related to such
9 distribution and use acknowledge that the software was developed
10 at Cygnus Support, Inc.  Cygnus Support, Inc. may not be used to
11 endorse or promote products derived from this software without
12 specific prior written permission.
13 THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 /*
18 FUNCTION
19 	<<memset>>---set an area of memory
20 
21 INDEX
22 	memset
23 
24 SYNOPSIS
25 	#include <string.h>
26 	void *memset(void *<[dst]>, int <[c]>, size_t <[length]>);
27 
28 DESCRIPTION
29 	This function converts the argument <[c]> into an unsigned
30 	char and fills the first <[length]> characters of the array
31 	pointed to by <[dst]> to the value.
32 
33 RETURNS
34 	<<memset>> returns the value of <[dst]>.
35 
36 PORTABILITY
37 <<memset>> is ANSI C.
38 
39     <<memset>> requires no supporting OS subroutines.
40 
41 QUICKREF
42 	memset ansi pure
43 */
44 
45 #include <string.h>
46 #include "local.h"
47 #include <stdint.h>
48 
49 #define LBLOCKSIZE (sizeof(long))
50 #define UNALIGNED(X)   ((uintptr_t)X & (LBLOCKSIZE - 1))
51 #define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE)
52 
53 #undef memset
54 
55 void *
56 __inhibit_loop_to_libcall
memset(void * m,int c,size_t n)57 memset (void *m,
58 	int c,
59 	size_t n)
60 {
61   char *s = (char *) m;
62 
63 #if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__)
64   unsigned int i;
65   unsigned long buffer;
66   unsigned long *aligned_addr;
67   unsigned int d = c & 0xff;	/* To avoid sign extension, copy C to an
68 				   unsigned variable.  */
69 
70   while (UNALIGNED (s))
71     {
72       if (n--)
73         *s++ = (char) c;
74       else
75         return m;
76     }
77 
78   if (!TOO_SMALL (n))
79     {
80       /* If we get this far, we know that n is large and s is word-aligned. */
81       aligned_addr = (unsigned long *) s;
82 
83       /* Store D into each char sized location in BUFFER so that
84          we can set large blocks quickly.  */
85       buffer = (d << 8) | d;
86       buffer |= (buffer << 16);
87       for (i = 32; i < LBLOCKSIZE * 8; i <<= 1)
88         buffer = (buffer << i) | buffer;
89 
90       /* Unroll the loop.  */
91       while (n >= LBLOCKSIZE*4)
92         {
93           *aligned_addr++ = buffer;
94           *aligned_addr++ = buffer;
95           *aligned_addr++ = buffer;
96           *aligned_addr++ = buffer;
97           n -= 4*LBLOCKSIZE;
98         }
99 
100       while (n >= LBLOCKSIZE)
101         {
102           *aligned_addr++ = buffer;
103           n -= LBLOCKSIZE;
104         }
105       /* Pick up the remainder with a bytewise loop.  */
106       s = (char*)aligned_addr;
107     }
108 
109 #endif /* not PREFER_SIZE_OVER_SPEED */
110 
111   while (n--)
112     *s++ = (char) c;
113 
114   return m;
115 }
116