root/mpich2/trunk/src/mpid/ch3/channels/nemesis/nemesis/include/mpid_nem_memdefs.h @ 4850

Revision 4850, 9.2 KB (checked in by buntinas, 5 months ago)

Remove restrict from memcpy implementation to quiet compiler warnings

Line 
1/* -*- Mode: C; c-basic-offset:4 ; -*- */
2/*
3 *  (C) 2006 by Argonne National Laboratory.
4 *      See COPYRIGHT in top-level directory.
5 */
6
7#ifndef MPID_MEMDEFS_H
8#define MPID_MEMDEFS_H
9#include <mpichconf.h>
10#include <mpimem.h>
11
12#if defined(HAVE_GCC_AND_PENTIUM_ASM)
13#define asm_memcpy(dst, src, n) do {                                                    \
14        const char *_p = (char *)(src);                                                 \
15        char *_q = (char *)(dst);                                                       \
16        size_t _nl = (size_t)(n) >> 2;                                                  \
17        __asm__ __volatile__ ("cld ; rep ; movsl ; movl %3,%0 ; rep ; movsb"            \
18                              : "+c" (_nl), "+S" (_p), "+D" (_q)                        \
19                              : "r" ((n) & 3) /* : "memory" is this needed?*/);         \
20    } while (0)
21
22/*
23   nt_memcpy (dst, src, len)
24   This performs a memcopy using non-temporal stores.  It's optimized
25   for ia_32 machines.
26
27   The general idea is to prefetch a block of the source data into the
28   cache, then read the data from the source buffer into 64-bit mmx
29   registers so that the data can be written to the destination buffer
30   using non-temporal move instructions.
31
32   This is done in three steps:  copy 8K or larger chunks, copy (8K,
33   128B] chunks, and copy the rest.
34
35   In the first step, the main loop prefetches an 8K chunk, by reading
36   one element from each cacheline.  Then we copy that 8K chunk, 64
37   bytes at a time (8bytes per mmx reg * 8 mmx regs) using
38   non-temporal stores.  Rinse and repeat.
39
40   The second step is essentially the same as the first, except that
41   the amount of data to be copied in that step is less than 8K, so we
42   prefetch all of the data.  These two steps could have been combined
43   but I think I saved some time by simplifying the main loop in step
44   one by not checking if we have to prefetch less than 8K.
45
46   The last step just copies whatever's left.
47   
48 */
49
50static inline void nt_memcpy (volatile void *dst, volatile const void *src, size_t len)
51{
52    void *dummy_dst;
53    void *dummy_src;
54   
55    int n;
56
57    /* copy in 8K chunks */
58    n = len & (-8*1024);
59    if (n)
60    {
61
62        __asm__ __volatile__ ("mov %4, %%ecx\n"
63                      ".set PREFETCHBLOCK, 1024\n" /* prefetch PREFETCHBLOCK number of 8-byte words */
64                      "lea (%%esi, %%ecx, 8), %%esi\n"
65                      "lea (%%edi, %%ecx, 8), %%edi\n"
66                 
67                      "neg %%ecx\n"
68                      "emms\n"
69                 
70                      "1:\n" /* main loop */
71
72                      /* eax is the prefetch loop iteration counter */
73                      "mov $PREFETCHBLOCK/16, %%eax\n"  /* only need to touch one element per cacheline, and we're doing two at once  */
74
75                      /* prefetch 2 cachelines at a time (128 bytes) */
76                      "2:\n" /* prefetch loop */
77                      "mov (%%esi, %%ecx, 8), %%edx\n"
78                      "mov 64(%%esi, %%ecx, 8), %%edx\n"
79                      "add $16, %%ecx\n" 
80                 
81                      "dec %%eax\n"
82                      "jnz 2b\n"
83                      "sub $PREFETCHBLOCK, %%ecx\n"
84
85                      /* eax is the copy loop iteration counter */
86                      "mov $PREFETCHBLOCK/8, %%eax\n"
87
88                      /* copy data 64 bytes at a time */
89                      "3:\n" /* copy loop */
90                      "movq (%%esi, %%ecx, 8), %%mm0\n"
91                      "movq 8(%%esi, %%ecx, 8), %%mm1\n"
92                      "movq 16(%%esi, %%ecx, 8), %%mm2\n"
93                      "movq 24(%%esi, %%ecx, 8), %%mm3\n"
94                      "movq 32(%%esi, %%ecx, 8), %%mm4\n"
95                      "movq 40(%%esi, %%ecx, 8), %%mm5\n"
96                      "movq 48(%%esi, %%ecx, 8), %%mm6\n"
97                      "movq 56(%%esi, %%ecx, 8), %%mm7\n"
98                 
99                      "movntq %%mm0, (%%edi, %%ecx, 8)\n"
100                      "movntq %%mm1, 8(%%edi, %%ecx, 8)\n"
101                      "movntq %%mm2, 16(%%edi, %%ecx, 8)\n"
102                      "movntq %%mm3, 24(%%edi, %%ecx, 8)\n"
103                      "movntq %%mm4, 32(%%edi, %%ecx, 8)\n"
104                      "movntq %%mm5, 40(%%edi, %%ecx, 8)\n"
105                      "movntq %%mm6, 48(%%edi, %%ecx, 8)\n"
106                      "movntq %%mm7, 56(%%edi, %%ecx, 8)\n"
107
108                      "add $8, %%ecx\n"
109                      "dec %%eax\n"
110                      "jnz 3b\n"
111
112                      "or %%ecx, %%ecx\n"
113                      "jnz 1b\n"
114
115                      "sfence\n"
116                      "emms\n"
117                      : "=D" (dummy_dst), "=S" (dummy_src)
118                      : "0" (dst), "1" (src), "g" (n >> 3)
119                      : "eax", "edx", "ecx"/* , "memory" is this needed? */);
120
121        src = (char *)src + n;
122        dst = (char *)dst + n;
123    }
124   
125    /* copy in 128byte chunks */
126    n = len & (8*1024 - 1) & -128;
127    if (n)
128    {
129
130        __asm__ __volatile__ ("mov %4, %%ecx\n"
131                      "lea (%%esi, %%ecx, 8), %%esi\n"
132                      "lea (%%edi, %%ecx, 8), %%edi\n"
133
134                      "push %%ecx\n"        /* save n */
135                         
136                      "mov %%ecx, %%eax\n" /* prefetch loopctr = n/128 */
137                      "shr $4, %%eax\n" 
138                 
139                      "neg %%ecx\n"
140                      "emms\n"
141
142                      /* prefetch all data to be copied 2 cachelines at a time (128 bytes)*/
143                      "1:\n" /* prefetch loop */
144                      "mov (%%esi, %%ecx, 8), %%edx\n"
145                      "mov 64(%%esi, %%ecx, 8), %%edx\n"
146                      "add $16, %%ecx\n"
147                 
148                      "dec %%eax\n"
149                      "jnz 1b\n"
150
151                      "pop %%ecx\n" /* restore n */
152
153                      "mov %%ecx, %%eax\n" /* write loopctr = n/64 */
154                      "shr $3, %%eax\n"
155                      "neg %%ecx\n"
156
157                      /* copy data 64 bytes at a time */
158                      "2:\n" /* copy loop */
159                      "movq (%%esi, %%ecx, 8), %%mm0\n"
160                      "movq 8(%%esi, %%ecx, 8), %%mm1\n"
161                      "movq 16(%%esi, %%ecx, 8), %%mm2\n"
162                      "movq 24(%%esi, %%ecx, 8), %%mm3\n"
163                      "movq 32(%%esi, %%ecx, 8), %%mm4\n"
164                      "movq 40(%%esi, %%ecx, 8), %%mm5\n"
165                      "movq 48(%%esi, %%ecx, 8), %%mm6\n"
166                      "movq 56(%%esi, %%ecx, 8), %%mm7\n"
167                 
168                      "movntq %%mm0, (%%edi, %%ecx, 8)\n"
169                      "movntq %%mm1, 8(%%edi, %%ecx, 8)\n"
170                      "movntq %%mm2, 16(%%edi, %%ecx, 8)\n"
171                      "movntq %%mm3, 24(%%edi, %%ecx, 8)\n"
172                      "movntq %%mm4, 32(%%edi, %%ecx, 8)\n"
173                      "movntq %%mm5, 40(%%edi, %%ecx, 8)\n"
174                      "movntq %%mm6, 48(%%edi, %%ecx, 8)\n"
175                      "movntq %%mm7, 56(%%edi, %%ecx, 8)\n"
176
177                      "add $8, %%ecx\n"
178                      "dec %%eax\n"
179                      "jnz 2b\n"
180
181                      "sfence\n"
182                      "emms\n"
183                      : "=D" (dummy_dst), "=S" (dummy_src) 
184                      : "0" (dst), "1" (src), "g" (n >> 3)
185                      : "eax", "edx", "ecx" /* , "memory" is this needed? */);
186        src = (char *)src + n;
187        dst = (char *)dst + n;
188    }
189   
190    /* copy leftover */
191    n = len & (128 - 1);
192    if (n)
193        asm_memcpy (dst, src, n);   
194}
195
196#define MPID_NEM_MEMCPY_CROSSOVER (63*1024)
197
198#define MPIU_Memcpy(a,b,c)  do {                                                                \
199        if (((c)) >= MPID_NEM_MEMCPY_CROSSOVER)                                                 \
200            nt_memcpy (a, b, c);                                                                \
201        else                                                                                    \
202            asm_memcpy (a, b, c);                                                               \
203    } while (0)
204
205#elif 0 && defined(HAVE_GCC_AND_X86_64_ASM)
206
207#define asm_memcpy(dst, src, n)  do {                                                            \
208        const char *_p = (char *)(src);                                                          \
209        char *_q = (char *)(dst);                                                                \
210        size_t _nq = n >> 3;                                                                     \
211        __asm__ __volatile__ ("cld ; rep ; movsq ; movl %3,%%ecx ; rep ; movsb"                  \
212                              : "+c" (_nq), "+S" (_p), "+D" (_q)                                 \
213                              : "r" ((uint32_t)((n) & 7)) /* : "memory" is this needed? */);     \
214    } while (0)
215
216static inline void amd64_cpy_nt (volatile void *dst, const volatile void *src, size_t n)
217{
218    size_t n32 = (n) >> 5;
219    size_t nleft = (n) & (32-1);
220   
221    if (n32)
222    {
223        __asm__ __volatile__ (".align 16  \n"
224                      "1:  \n"
225                      "mov (%1), %%r8  \n"
226                      "mov 8(%1), %%r9  \n"
227                      "add $32, %1  \n"
228                      "movnti %%r8, (%2)  \n"
229                      "movnti %%r9, 8(%2)  \n"
230                      "add $32, %2  \n"
231                      "mov -16(%1), %%r8  \n"
232                      "mov -8(%1), %%r9  \n"
233                      "dec %0  \n"
234                      "movnti %%r8, -16(%2)  \n"
235                      "movnti %%r9, -8(%2)  \n"
236                      "jnz 1b  \n"
237                      "sfence  \n"
238                      "mfence  \n"
239                      : "+a" (n32), "+S" (src), "+D" (dst)
240                      : : "r8", "r9" /*, "memory" is this needed? */);
241    }
242   
243    if (nleft)
244    {
245        memcpy ((void *)dst, (void *)src, nleft);
246    }
247}
248
249static inline
250void volatile_memcpy (volatile void *restrict dst, volatile const void *restrict src, size_t n)
251{
252    MPIUI_Memcpy ((void *)dst, (const void *)src, n);
253}
254
255#define MPID_NEM_MEMCPY_CROSSOVER (32*1024)
256#define MPIU_Memcpy(a,b,c) do {                 \
257        if ((c) >= MPID_NEM_MEMCPY_CROSSOVER)   \
258            amd64_cpy_nt(a, b, c);              \
259        else                                    \
260            volatile_memcpy(a, b, c);           \
261    } while (0)
262/* #define MPID_NEM_MEMCPY(a,b,c) (((c) < MPID_NEM_MEMCPY_CROSSOVER) ? memcpy(a, b, c) : amd64_cpy_nt(a, b, c)) */
263/* #define MPID_NEM_MEMCPY(a,b,c) amd64_cpy_nt(a, b, c) */
264/* #define MPID_NEM_MEMCPY(a,b,c) memcpy (a, b, c) */
265
266#else
267/* #define MPIU_Memcpy(dst, src, n) do { volatile void * restrict d = (dst); volatile const void *restrict s = (src); MPIUI_Memcpy((void *)d, (const void *)s, n); }while (0) */
268#define MPIU_Memcpy(dst, src, n) MPIUI_Memcpy(dst, src, n)
269#endif
270
271#endif /* MPID_MEMDEFS_H */
Note: See TracBrowser for help on using the browser.