]> granicus.if.org Git - zfs/blob - module/zcommon/zfs_fletcher_superscalar4.c
Project Quota on ZFS
[zfs] / module / zcommon / zfs_fletcher_superscalar4.c
1 /*
2  * Implement fast Fletcher4 using superscalar pipelines.
3  *
4  * Use regular C code to compute
5  * Fletcher4 in four incremental 64-bit parallel accumulator streams,
6  * and then combine the streams to form the final four checksum words.
7  * This implementation is a derivative of the AVX SIMD implementation by
8  * James Guilford and Jinshan Xiong from Intel (see zfs_fletcher_intel.c).
9  *
10  * Copyright (C) 2016 Romain Dolbeau.
11  *
12  * Authors:
13  *      Romain Dolbeau <romain.dolbeau@atos.net>
14  *
15  * This software is available to you under a choice of one of two
16  * licenses.  You may choose to be licensed under the terms of the GNU
17  * General Public License (GPL) Version 2, available from the file
18  * COPYING in the main directory of this source tree, or the
19  * OpenIB.org BSD license below:
20  *
21  *     Redistribution and use in source and binary forms, with or
22  *     without modification, are permitted provided that the following
23  *     conditions are met:
24  *
25  *      - Redistributions of source code must retain the above
26  *        copyright notice, this list of conditions and the following
27  *        disclaimer.
28  *
29  *      - Redistributions in binary form must reproduce the above
30  *        copyright notice, this list of conditions and the following
31  *        disclaimer in the documentation and/or other materials
32  *        provided with the distribution.
33  *
34  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
35  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
36  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
37  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
38  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
39  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
40  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
41  * SOFTWARE.
42  */
43
44 #include <sys/byteorder.h>
45 #include <sys/spa_checksum.h>
46 #include <zfs_fletcher.h>
47 #include <strings.h>
48
49 static void
50 fletcher_4_superscalar4_init(fletcher_4_ctx_t *ctx)
51 {
52         bzero(ctx->superscalar, 4 * sizeof (zfs_fletcher_superscalar_t));
53 }
54
55 static void
56 fletcher_4_superscalar4_fini(fletcher_4_ctx_t *ctx, zio_cksum_t *zcp)
57 {
58         uint64_t A, B, C, D;
59
60         A = ctx->superscalar[0].v[0] + ctx->superscalar[0].v[1] +
61             ctx->superscalar[0].v[2] + ctx->superscalar[0].v[3];
62         B = 0 - ctx->superscalar[0].v[1] - 2 * ctx->superscalar[0].v[2] -
63             3 * ctx->superscalar[0].v[3] + 4 * ctx->superscalar[1].v[0] +
64             4 * ctx->superscalar[1].v[1] + 4 * ctx->superscalar[1].v[2] +
65             4 * ctx->superscalar[1].v[3];
66
67         C = ctx->superscalar[0].v[2] + 3 * ctx->superscalar[0].v[3] -
68             6 * ctx->superscalar[1].v[0] - 10 * ctx->superscalar[1].v[1] -
69             14 * ctx->superscalar[1].v[2] - 18 * ctx->superscalar[1].v[3] +
70             16 * ctx->superscalar[2].v[0] + 16 * ctx->superscalar[2].v[1] +
71             16 * ctx->superscalar[2].v[2] + 16 * ctx->superscalar[2].v[3];
72
73         D = 0 - ctx->superscalar[0].v[3] + 4 * ctx->superscalar[1].v[0] +
74             10 * ctx->superscalar[1].v[1] + 20 * ctx->superscalar[1].v[2] +
75             34 * ctx->superscalar[1].v[3] - 48 * ctx->superscalar[2].v[0] -
76             64 * ctx->superscalar[2].v[1] - 80 * ctx->superscalar[2].v[2] -
77             96 * ctx->superscalar[2].v[3] + 64 * ctx->superscalar[3].v[0] +
78             64 * ctx->superscalar[3].v[1] + 64 * ctx->superscalar[3].v[2] +
79             64 * ctx->superscalar[3].v[3];
80
81         ZIO_SET_CHECKSUM(zcp, A, B, C, D);
82 }
83
84 static void
85 fletcher_4_superscalar4_native(fletcher_4_ctx_t *ctx,
86     const void *buf, uint64_t size)
87 {
88         const uint32_t *ip = buf;
89         const uint32_t *ipend = ip + (size / sizeof (uint32_t));
90         uint64_t a, b, c, d;
91         uint64_t a2, b2, c2, d2;
92         uint64_t a3, b3, c3, d3;
93         uint64_t a4, b4, c4, d4;
94
95         a = ctx->superscalar[0].v[0];
96         b = ctx->superscalar[1].v[0];
97         c = ctx->superscalar[2].v[0];
98         d = ctx->superscalar[3].v[0];
99         a2 = ctx->superscalar[0].v[1];
100         b2 = ctx->superscalar[1].v[1];
101         c2 = ctx->superscalar[2].v[1];
102         d2 = ctx->superscalar[3].v[1];
103         a3 = ctx->superscalar[0].v[2];
104         b3 = ctx->superscalar[1].v[2];
105         c3 = ctx->superscalar[2].v[2];
106         d3 = ctx->superscalar[3].v[2];
107         a4 = ctx->superscalar[0].v[3];
108         b4 = ctx->superscalar[1].v[3];
109         c4 = ctx->superscalar[2].v[3];
110         d4 = ctx->superscalar[3].v[3];
111
112         for (; ip < ipend; ip += 4) {
113                 a += ip[0];
114                 a2 += ip[1];
115                 a3 += ip[2];
116                 a4 += ip[3];
117                 b += a;
118                 b2 += a2;
119                 b3 += a3;
120                 b4 += a4;
121                 c += b;
122                 c2 += b2;
123                 c3 += b3;
124                 c4 += b4;
125                 d += c;
126                 d2 += c2;
127                 d3 += c3;
128                 d4 += c4;
129         }
130
131         ctx->superscalar[0].v[0] = a;
132         ctx->superscalar[1].v[0] = b;
133         ctx->superscalar[2].v[0] = c;
134         ctx->superscalar[3].v[0] = d;
135         ctx->superscalar[0].v[1] = a2;
136         ctx->superscalar[1].v[1] = b2;
137         ctx->superscalar[2].v[1] = c2;
138         ctx->superscalar[3].v[1] = d2;
139         ctx->superscalar[0].v[2] = a3;
140         ctx->superscalar[1].v[2] = b3;
141         ctx->superscalar[2].v[2] = c3;
142         ctx->superscalar[3].v[2] = d3;
143         ctx->superscalar[0].v[3] = a4;
144         ctx->superscalar[1].v[3] = b4;
145         ctx->superscalar[2].v[3] = c4;
146         ctx->superscalar[3].v[3] = d4;
147 }
148
149 static void
150 fletcher_4_superscalar4_byteswap(fletcher_4_ctx_t *ctx,
151     const void *buf, uint64_t size)
152 {
153         const uint32_t *ip = buf;
154         const uint32_t *ipend = ip + (size / sizeof (uint32_t));
155         uint64_t a, b, c, d;
156         uint64_t a2, b2, c2, d2;
157         uint64_t a3, b3, c3, d3;
158         uint64_t a4, b4, c4, d4;
159
160         a = ctx->superscalar[0].v[0];
161         b = ctx->superscalar[1].v[0];
162         c = ctx->superscalar[2].v[0];
163         d = ctx->superscalar[3].v[0];
164         a2 = ctx->superscalar[0].v[1];
165         b2 = ctx->superscalar[1].v[1];
166         c2 = ctx->superscalar[2].v[1];
167         d2 = ctx->superscalar[3].v[1];
168         a3 = ctx->superscalar[0].v[2];
169         b3 = ctx->superscalar[1].v[2];
170         c3 = ctx->superscalar[2].v[2];
171         d3 = ctx->superscalar[3].v[2];
172         a4 = ctx->superscalar[0].v[3];
173         b4 = ctx->superscalar[1].v[3];
174         c4 = ctx->superscalar[2].v[3];
175         d4 = ctx->superscalar[3].v[3];
176
177         for (; ip < ipend; ip += 4) {
178                 a += BSWAP_32(ip[0]);
179                 a2 += BSWAP_32(ip[1]);
180                 a3 += BSWAP_32(ip[2]);
181                 a4 += BSWAP_32(ip[3]);
182                 b += a;
183                 b2 += a2;
184                 b3 += a3;
185                 b4 += a4;
186                 c += b;
187                 c2 += b2;
188                 c3 += b3;
189                 c4 += b4;
190                 d += c;
191                 d2 += c2;
192                 d3 += c3;
193                 d4 += c4;
194         }
195
196         ctx->superscalar[0].v[0] = a;
197         ctx->superscalar[1].v[0] = b;
198         ctx->superscalar[2].v[0] = c;
199         ctx->superscalar[3].v[0] = d;
200         ctx->superscalar[0].v[1] = a2;
201         ctx->superscalar[1].v[1] = b2;
202         ctx->superscalar[2].v[1] = c2;
203         ctx->superscalar[3].v[1] = d2;
204         ctx->superscalar[0].v[2] = a3;
205         ctx->superscalar[1].v[2] = b3;
206         ctx->superscalar[2].v[2] = c3;
207         ctx->superscalar[3].v[2] = d3;
208         ctx->superscalar[0].v[3] = a4;
209         ctx->superscalar[1].v[3] = b4;
210         ctx->superscalar[2].v[3] = c4;
211         ctx->superscalar[3].v[3] = d4;
212 }
213
214 static boolean_t fletcher_4_superscalar4_valid(void)
215 {
216         return (B_TRUE);
217 }
218
219 const fletcher_4_ops_t fletcher_4_superscalar4_ops = {
220         .init_native = fletcher_4_superscalar4_init,
221         .compute_native = fletcher_4_superscalar4_native,
222         .fini_native = fletcher_4_superscalar4_fini,
223         .init_byteswap = fletcher_4_superscalar4_init,
224         .compute_byteswap = fletcher_4_superscalar4_byteswap,
225         .fini_byteswap = fletcher_4_superscalar4_fini,
226         .valid = fletcher_4_superscalar4_valid,
227         .name = "superscalar4"
228 };