comparison utils/genaltivec.c @ 41:c6e0df09b86f default tip

*: performance improvements with old GCC, reimplement altivec
author Paper <paper@tflc.us>
date Mon, 28 Apr 2025 16:31:59 -0400
parents
children
comparison
equal deleted inserted replaced
40:55cadb1fac4b 41:c6e0df09b86f
1 /**
2 * vec - a tiny SIMD vector library in C99
3 *
4 * Copyright (c) 2024-2025 Paper
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 **/
24
25 /* Use this file to generate include/vec/impl/ppc/altivec.h !!
26 *
27 * `gcc -o genaltivec genaltivec.c` */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <ctype.h>
33
34 #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
35
36 /* ------------------------------------------------------------------------ */
37
38 /* #define USE_VSX_EXTENSIONS */
39
40 enum op {
41 /* return vector, take in a integer */
42 OP_SPLAT = 0,
43
44 /* return vector, take in an array */
45 OP_LOAD_ALIGNED,
46 OP_LOAD,
47
48 /* void, take in vector and array */
49 OP_STORE_ALIGNED,
50 OP_STORE,
51
52 /* return vector, takes in two vectors */
53 OP_ADD,
54 OP_SUB,
55 OP_MUL,
56 OP_AND,
57 OP_OR,
58 OP_XOR,
59 OP_CMPLT,
60 OP_CMPEQ,
61 OP_CMPGT,
62 #ifdef USE_VSX_EXTENSIONS
63 OP_CMPLE,
64 OP_CMPGE,
65 #endif
66 OP_MIN,
67 OP_MAX,
68 OP_AVG,
69
70 /* return vector, takes in a vector and an explicitly unsigned vector */
71 OP_LSHIFT,
72 OP_LRSHIFT,
73 OP_RSHIFT,
74
75 OP_FINAL_,
76
77 /* unimplemented, no altivec version :) */
78 OP_NOT,
79 };
80
81 /* convert op -> string */
82 static struct {
83 const char *u;
84 const char *l;
85 } op_names[] = {
86 [OP_SPLAT] = {"SPLAT", "splat"},
87 [OP_LOAD_ALIGNED] = {"LOAD_ALIGNED", "load_aligned"},
88 [OP_LOAD] = {"LOAD", "load"},
89 [OP_STORE_ALIGNED] = {"STORE_ALIGNED", "store_aligned"},
90 [OP_STORE] = {"STORE", "store"},
91 [OP_ADD] = {"ADD", "add"},
92 [OP_SUB] = {"SUB", "sub"},
93 [OP_MUL] = {"MUL", "mul"},
94 [OP_AVG] = {"AVG", "avg"},
95 [OP_AND] = {"AND", "and"},
96 [OP_OR] = {"OR", "or"},
97 [OP_XOR] = {"XOR", "xor"},
98 [OP_NOT] = {"NOT", "not"},
99 [OP_CMPLT] = {"CMPLT", "cmplt"},
100 [OP_CMPEQ] = {"CMPEQ", "cmpeq"},
101 [OP_CMPGT] = {"CMPGT", "cmpgt"},
102 #ifdef USE_VSX_EXTENSIONS
103 [OP_CMPLE] = {"CMPLE", "cmple"},
104 [OP_CMPGE] = {"CMPGE", "cmpge"},
105 #endif
106 [OP_MIN] = {"MIN", "min"},
107 [OP_MAX] = {"MAX", "max"},
108 [OP_RSHIFT] = {"RSHIFT", "rshift"},
109 [OP_LRSHIFT] = {"LRSHIFT", "lrshift"},
110 [OP_LSHIFT] = {"LSHIFT", "lshift"},
111 };
112
113 #define UPSIGN(x) ((x) ? "" : "U")
114 #define LOSIGN(x) ((x) ? "" : "u")
115
116 static void print_gcc_op(enum op op, int is_signed, int bits, int size)
117 {
118 int i;
119
120 /* compatibility with ancient gcc */
121 switch (op) {
122 case OP_MUL:
123 puts("#ifdef vec_mul");
124 break;
125 case OP_SPLAT:
126 puts("#ifdef vec_splats");
127 break;
128 default:
129 break;
130 }
131
132 printf("#ifndef V%sINT%dx%d_%s_DEFINED\n", UPSIGN(is_signed), bits, size, op_names[op].u);
133
134 printf("VEC_FUNC_IMPL ");
135
136 /* first; the return value */
137 switch (op) {
138 case OP_SPLAT:
139 case OP_LOAD_ALIGNED:
140 case OP_LOAD:
141 case OP_ADD:
142 case OP_SUB:
143 case OP_MUL:
144 case OP_AND:
145 case OP_OR:
146 case OP_XOR:
147 case OP_CMPLT:
148 case OP_CMPEQ:
149 case OP_CMPGT:
150 #ifdef USE_VSX_EXTENSIONS
151 case OP_CMPLE:
152 case OP_CMPGE:
153 #endif
154 case OP_MIN:
155 case OP_MAX:
156 case OP_AVG:
157 case OP_RSHIFT:
158 case OP_LRSHIFT:
159 case OP_LSHIFT:
160 case OP_NOT:
161 printf("v%sint%dx%d", LOSIGN(is_signed), bits, size);
162 break;
163 case OP_STORE_ALIGNED:
164 case OP_STORE:
165 printf("void");
166 break;
167 }
168
169 /* whitespace and function name */
170 printf(" v%sint%dx%d_%s(", LOSIGN(is_signed), bits, size, op_names[op].l);
171
172 /* parameters */
173 switch (op) {
174 case OP_SPLAT:
175 printf("vec_%sint%d x", LOSIGN(is_signed), bits);
176 break;
177 case OP_LOAD_ALIGNED:
178 case OP_LOAD:
179 printf("const vec_%sint%d x[%d]", LOSIGN(is_signed), bits, size);
180 break;
181 case OP_STORE_ALIGNED:
182 case OP_STORE:
183 printf("v%sint%dx%d vec, vec_%sint%d arr[%d]", LOSIGN(is_signed), bits, size, LOSIGN(is_signed), bits, size);
184 break;
185 case OP_ADD:
186 case OP_SUB:
187 case OP_MUL:
188 case OP_AND:
189 case OP_OR:
190 case OP_XOR:
191 case OP_CMPLT:
192 case OP_CMPEQ:
193 case OP_CMPGT:
194 #ifdef USE_VSX_EXTENSIONS
195 case OP_CMPLE:
196 case OP_CMPGE:
197 #endif
198 case OP_MIN:
199 case OP_MAX:
200 case OP_AVG:
201 printf("v%sint%dx%d vec1, v%sint%dx%d vec2", LOSIGN(is_signed), bits, size, LOSIGN(is_signed), bits, size);
202 break;
203 case OP_RSHIFT:
204 case OP_LRSHIFT:
205 case OP_LSHIFT:
206 printf("v%sint%dx%d vec1, vuint%dx%d vec2", LOSIGN(is_signed), bits, size, bits, size);
207 break;
208 case OP_NOT:
209 printf("v%sint%dx%d vec", LOSIGN(is_signed), bits, size);
210 break;
211 }
212
213 puts(")\n{");
214
215 switch (op) {
216 case OP_SPLAT:
217 printf("\tv%sint%dx%d vec;\n", LOSIGN(is_signed), bits, size);
218 printf("\tvec.altivec = vec_splats(x);\n");
219 printf("\treturn vec;\n");
220 break;
221 case OP_LOAD_ALIGNED:
222 printf("\tv%sint%dx%d vec;\n", LOSIGN(is_signed), bits, size);
223 puts("\tvec.altivec = vec_ld(0, x);");
224 printf("\treturn vec;\n");
225 break;
226 case OP_LOAD:
227 printf("\tv%sint%dx%d vec;\n", LOSIGN(is_signed), bits, size);
228 puts("\tvec.altivec = vec_perm(vec_ld(0, x), vec_ld(16, x), vec_lvsl(0, x));");
229 printf("\treturn vec;\n");
230 break;
231 case OP_STORE_ALIGNED:
232 puts("\tvec_st(vec.altivec, 0, arr);");
233 break;
234 case OP_STORE:
235 /* ??? */
236 puts("\tmemcpy(arr, &vec, sizeof(vec));");
237 break;
238 case OP_ADD:
239 case OP_SUB:
240 case OP_MUL:
241 case OP_AND:
242 case OP_OR:
243 case OP_XOR:
244 case OP_AVG:
245 case OP_CMPLT:
246 case OP_CMPEQ:
247 case OP_CMPGT:
248 #ifdef USE_VSX_EXTENSIONS
249 case OP_CMPLE:
250 case OP_CMPGE:
251 #endif
252 case OP_LSHIFT:
253 case OP_LRSHIFT:
254 case OP_RSHIFT:
255 case OP_MIN:
256 case OP_MAX: {
257 static const char *op_altivec[OP_LRSHIFT - OP_ADD + 1] = {"add", "sub", "mul", "and", "or", "xor", "cmplt", "cmpeq", "cmpgt",
258 #ifdef USE_VSX_EXTENSIONS
259 "cmple",
260 "cmpge",
261 #endif
262 "min", "max", "avg", "sl", "sr"};
263 static const char *types[] = {"char", "short", NULL, "int"};
264
265 printf("\tv%sint%dx%d vec;\n", LOSIGN(is_signed), bits, size);
266 if (op == OP_RSHIFT) {
267 printf("\tvec.altivec = vec_sr%s(vec1.altivec, vec2.altivec);\n", (is_signed) ? "a" : "");
268 } else {
269 printf("\tvec.altivec = (vector %s %s)vec_%s(vec1.altivec, vec2.altivec);\n", (is_signed) ? "signed" : "unsigned", types[(bits / 8) - 1], op_altivec[op - OP_ADD]);
270 }
271 printf("\treturn vec;\n");
272 break;
273 }
274 default:
275 printf("#error implement this operation");
276 break;
277 }
278
279 /* end function definition */
280 puts("}");
281
282 printf("# define V%sINT%dx%d_%s_DEFINED\n", UPSIGN(is_signed), bits, size, op_names[op].u);
283 puts("#endif");
284
285 switch (op) {
286 case OP_SPLAT:
287 case OP_MUL:
288 puts("#endif");
289 break;
290 default:
291 break;
292 }
293 }
294
295 static inline void print_ops(int is_signed, int bits, int size)
296 {
297 int i;
298
299 printf("\n\n/* v%sint%dx%d */\n\n", (is_signed ? "u" : ""), bits, size);
300
301 for (i = 0; i < OP_FINAL_; i++)
302 print_gcc_op(i, is_signed, bits, size);
303 }
304
305 #ifdef USE_VSX_EXTENSIONS
306 # define HEADER_GUARD_NAME "VSX"
307 #else
308 # define HEADER_GUARD_NAME "ALTIVEC"
309 #endif
310
311 static const char *header =
312 "/**\n"
313 " * vec - a tiny SIMD vector library in C99\n"
314 " * \n"
315 " * Copyright (c) 2024-2025 Paper\n"
316 " * \n"
317 " * Permission is hereby granted, free of charge, to any person obtaining a copy\n"
318 " * of this software and associated documentation files (the \"Software\"), to deal\n"
319 " * in the Software without restriction, including without limitation the rights\n"
320 " * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n"
321 " * copies of the Software, and to permit persons to whom the Software is\n"
322 " * furnished to do so, subject to the following conditions:\n"
323 " * \n"
324 " * The above copyright notice and this permission notice shall be included in all\n"
325 " * copies or substantial portions of the Software.\n"
326 " * \n"
327 " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n"
328 " * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n"
329 " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n"
330 " * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n"
331 " * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n"
332 " * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n"
333 " * SOFTWARE.\n"
334 "**/\n"
335 "\n"
336 "/* This file is automatically generated! Do not edit it directly!\n"
337 " * Edit the code that generates it in utils/genaltivec.c --paper */\n"
338 "\n"
339 "#ifndef VEC_IMPL_PPC_" HEADER_GUARD_NAME "_H_\n"
340 "#define VEC_IMPL_PPC_" HEADER_GUARD_NAME "_H_\n"
341 "\n";
342
343 static const char *footer =
344 "#endif /* VEC_IMPL_PPC_" HEADER_GUARD_NAME "_H_ */\n";
345
346 int main(void)
347 {
348 static struct {
349 int bits, size;
350 } defs[] = {
351 /* -- 8-bit */
352 {8, 16},
353 /* -- 16-bit */
354 {16, 8},
355
356 /* -- 32-bit */
357 {32, 4},
358
359 #ifdef USE_VSX_EXTENSIONS
360 /* -- 64-bit */
361 {64, 2},
362 #endif
363 };
364 int i;
365
366 puts(header);
367
368 for (i = 0; i < ARRAY_SIZE(defs); i++) {
369 print_ops(1, defs[i].bits, defs[i].size);
370 print_ops(0, defs[i].bits, defs[i].size);
371 }
372
373 puts(footer);
374 }