Replace FSF snail mail address by URL.
[jlayton/glibc.git] / sysdeps / tile / tilegx / memset.c
1 /* Copyright (C) 2011 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library.  If not, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #include <arch/chip.h>
20 #include <string.h>
21 #include <stdint.h>
22
23 void *
24 __memset (void *s, int c, size_t n)
25 {
26   uint64_t *out64;
27   int n64, to_align64;
28   uint64_t v64;
29   uint8_t *out8 = s;
30
31   /* Experimentation shows that a trivial tight loop is a win up until
32      around a size of 20, where writing a word at a time starts to win.  */
33 #define BYTE_CUTOFF 20
34
35 #if BYTE_CUTOFF < 7
36   /* This must be at least at least this big, or some code later
37      on doesn't work.  */
38 # error "BYTE_CUTOFF is too small."
39 #endif
40
41   if (n < BYTE_CUTOFF)
42     {
43       /* Strangely, this turns out to be the tightest way to write
44          this loop.  */
45       if (n != 0)
46         {
47           do
48             {
49               /* Strangely, combining these into one line performs worse.  */
50               *out8 = c;
51               out8++;
52             }
53           while (--n != 0);
54         }
55
56       return s;
57     }
58
59   /* Align 'out8'. We know n >= 7 so this won't write past the end.  */
60   while (((uintptr_t) out8 & 7) != 0)
61     {
62       *out8++ = c;
63       --n;
64     }
65
66   /* Align 'n'. */
67   while (n & 7)
68     out8[--n] = c;
69
70   out64 = (uint64_t *) out8;
71   n64 = n >> 3;
72
73   /* Tile input byte out to 64 bits. */
74   v64 = 0x0101010101010101ULL * (uint8_t) c;
75
76   /* This must be at least 8 or the following loop doesn't work. */
77 #define CACHE_LINE_SIZE_IN_DOUBLEWORDS (CHIP_L2_LINE_SIZE() / 8)
78
79   /* Determine how many words we need to emit before the 'out32'
80      pointer becomes aligned modulo the cache line size.  */
81   to_align64 = (-((uintptr_t) out64 >> 3)) &
82     (CACHE_LINE_SIZE_IN_DOUBLEWORDS - 1);
83
84   /* Only bother aligning and using wh64 if there is at least
85      one full cache line to process.  This check also prevents
86      overrunning the end of the buffer with alignment words.  */
87   if (to_align64 <= n64 - CACHE_LINE_SIZE_IN_DOUBLEWORDS)
88     {
89       int lines_left;
90
91       /* Align out64 mod the cache line size so we can use wh64. */
92       n64 -= to_align64;
93       for (; to_align64 != 0; to_align64--)
94         {
95           *out64 = v64;
96           out64++;
97         }
98
99       /* Use unsigned divide to turn this into a right shift. */
100       lines_left = (unsigned) n64 / CACHE_LINE_SIZE_IN_DOUBLEWORDS;
101
102       do
103         {
104           /* Only wh64 a few lines at a time, so we don't exceed the
105              maximum number of victim lines.  */
106           int x = ((lines_left < CHIP_MAX_OUTSTANDING_VICTIMS ()) ? lines_left
107                    : CHIP_MAX_OUTSTANDING_VICTIMS ());
108           uint64_t *wh = out64;
109           int i = x;
110           int j;
111
112           lines_left -= x;
113
114           do
115             {
116               __insn_wh64 (wh);
117               wh += CACHE_LINE_SIZE_IN_DOUBLEWORDS;
118             }
119           while (--i);
120
121           for (j = x * (CACHE_LINE_SIZE_IN_DOUBLEWORDS / 4); j != 0; j--)
122             {
123               *out64++ = v64;
124               *out64++ = v64;
125               *out64++ = v64;
126               *out64++ = v64;
127             }
128         }
129       while (lines_left != 0);
130
131       /* We processed all full lines above, so only this many
132          words remain to be processed.  */
133       n64 &= CACHE_LINE_SIZE_IN_DOUBLEWORDS - 1;
134     }
135
136   /* Now handle any leftover values. */
137   if (n64 != 0)
138     {
139       do
140         {
141           *out64 = v64;
142           out64++;
143         }
144       while (--n64 != 0);
145     }
146
147   return s;
148 }
149 weak_alias (__memset, memset)
150 libc_hidden_builtin_def (memset)