comparison utils/genaltivec.c @ 45:7955bed1d169 default tip

*: add preliminary floating point support no x86 intrinsics just yet, but I did add altivec since it's (arguably) the simplest :)
author Paper <paper@tflc.us>
date Wed, 30 Apr 2025 18:36:38 -0400
parents b0a3f0248ecc
children
comparison
equal deleted inserted replaced
44:b0a3f0248ecc 45:7955bed1d169
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 #define LOAVSIGN(x) ((x) ? "s" : "u")
117
118 static void print_gcc_op(enum op op, int is_signed, int bits, int size)
119 {
120 int i;
121
122 /* compatibility with ancient gcc */
123 switch (op) {
124 case OP_MUL:
125 puts("#ifdef vec_mul");
126 break;
127 case OP_SPLAT:
128 printf("#if defined(vec_splats) || defined(vec_splat_%s%d)\n", (is_signed) ? "s" : "u", bits);
129 break;
130 default:
131 break;
132 }
133
134 printf("#ifndef V%sINT%dx%d_%s_DEFINED\n", UPSIGN(is_signed), bits, size, op_names[op].u);
135
136 printf("VEC_FUNC_IMPL ");
137
138 /* first; the return value */
139 switch (op) {
140 case OP_SPLAT:
141 case OP_LOAD_ALIGNED:
142 case OP_LOAD:
143 case OP_ADD:
144 case OP_SUB:
145 case OP_MUL:
146 case OP_AND:
147 case OP_OR:
148 case OP_XOR:
149 case OP_CMPLT:
150 case OP_CMPEQ:
151 case OP_CMPGT:
152 #ifdef USE_VSX_EXTENSIONS
153 case OP_CMPLE:
154 case OP_CMPGE:
155 #endif
156 case OP_MIN:
157 case OP_MAX:
158 case OP_AVG:
159 case OP_RSHIFT:
160 case OP_LRSHIFT:
161 case OP_LSHIFT:
162 case OP_NOT:
163 printf("v%sint%dx%d", LOSIGN(is_signed), bits, size);
164 break;
165 case OP_STORE_ALIGNED:
166 case OP_STORE:
167 printf("void");
168 break;
169 }
170
171 /* whitespace and function name */
172 printf(" v%sint%dx%d_%s(", LOSIGN(is_signed), bits, size, op_names[op].l);
173
174 /* parameters */
175 switch (op) {
176 case OP_SPLAT:
177 printf("vec_%sint%d x", LOSIGN(is_signed), bits);
178 break;
179 case OP_LOAD_ALIGNED:
180 case OP_LOAD:
181 printf("const vec_%sint%d x[%d]", LOSIGN(is_signed), bits, size);
182 break;
183 case OP_STORE_ALIGNED:
184 case OP_STORE:
185 printf("v%sint%dx%d vec, vec_%sint%d arr[%d]", LOSIGN(is_signed), bits, size, LOSIGN(is_signed), bits, size);
186 break;
187 case OP_ADD:
188 case OP_SUB:
189 case OP_MUL:
190 case OP_AND:
191 case OP_OR:
192 case OP_XOR:
193 case OP_CMPLT:
194 case OP_CMPEQ:
195 case OP_CMPGT:
196 #ifdef USE_VSX_EXTENSIONS
197 case OP_CMPLE:
198 case OP_CMPGE:
199 #endif
200 case OP_MIN:
201 case OP_MAX:
202 case OP_AVG:
203 printf("v%sint%dx%d vec1, v%sint%dx%d vec2", LOSIGN(is_signed), bits, size, LOSIGN(is_signed), bits, size);
204 break;
205 case OP_RSHIFT:
206 case OP_LRSHIFT:
207 case OP_LSHIFT:
208 printf("v%sint%dx%d vec1, vuint%dx%d vec2", LOSIGN(is_signed), bits, size, bits, size);
209 break;
210 case OP_NOT:
211 printf("v%sint%dx%d vec", LOSIGN(is_signed), bits, size);
212 break;
213 }
214
215 puts(")\n{");
216
217 switch (op) {
218 case OP_SPLAT:
219 printf("\tv%sint%dx%d vec;\n", LOSIGN(is_signed), bits, size);
220 puts("\tvec.altivec = vec_splats(x);");
221 puts("\treturn vec;");
222 break;
223 case OP_LOAD_ALIGNED:
224 printf("\tv%sint%dx%d vec;\n", LOSIGN(is_signed), bits, size);
225 puts("\tvec.altivec = vec_ld(0, x);");
226 puts("\treturn vec;");
227 break;
228 case OP_LOAD:
229 printf("\tv%sint%dx%d vec;\n", LOSIGN(is_signed), bits, size);
230 puts("\tvec.altivec = vec_perm(vec_ld(0, x), vec_ld(16, x), vec_lvsl(0, x));");
231 puts("\treturn vec;");
232 break;
233 case OP_STORE_ALIGNED:
234 puts("\tvec_st(vec.altivec, 0, arr);");
235 break;
236 case OP_STORE:
237 /* ??? */
238 puts("\tmemcpy(arr, &vec, sizeof(vec));");
239 break;
240 case OP_ADD:
241 case OP_SUB:
242 case OP_MUL:
243 case OP_AND:
244 case OP_OR:
245 case OP_XOR:
246 case OP_AVG:
247 case OP_CMPLT:
248 case OP_CMPEQ:
249 case OP_CMPGT:
250 #ifdef USE_VSX_EXTENSIONS
251 case OP_CMPLE:
252 case OP_CMPGE:
253 #endif
254 case OP_LSHIFT:
255 case OP_LRSHIFT:
256 case OP_RSHIFT:
257 case OP_MIN:
258 case OP_MAX: {
259 static const char *op_altivec[OP_LRSHIFT - OP_ADD + 1] = {"add", "sub", "mul", "and", "or", "xor", "cmplt", "cmpeq", "cmpgt",
260 #ifdef USE_VSX_EXTENSIONS
261 "cmple",
262 "cmpge",
263 #endif
264 "min", "max", "avg", "sl", "sr"};
265 static const char *types[] = {"char", "short", NULL, "int"};
266
267 printf("\tv%sint%dx%d vec;\n", LOSIGN(is_signed), bits, size);
268 if (op == OP_RSHIFT) {
269 printf("\tvec.altivec = vec_sr%s(vec1.altivec, vec2.altivec);\n", (is_signed) ? "a" : "");
270 } else {
271 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]);
272 }
273 puts("\treturn vec;");
274 break;
275 }
276 default:
277 printf("#error implement this operation");
278 break;
279 }
280
281 /* end function definition */
282 puts("}");
283
284 printf("# define V%sINT%dx%d_%s_DEFINED\n", UPSIGN(is_signed), bits, size, op_names[op].u);
285 puts("#endif");
286
287 switch (op) {
288 case OP_SPLAT:
289 case OP_MUL:
290 puts("#endif");
291 break;
292 default:
293 break;
294 }
295 }
296
297 static inline void print_ops(int is_signed, int bits, int size)
298 {
299 int i;
300
301 printf("\n\n/* v%sint%dx%d */\n\n", (is_signed ? "u" : ""), bits, size);
302
303 for (i = 0; i < OP_FINAL_; i++)
304 print_gcc_op(i, is_signed, bits, size);
305 }
306
307 #ifdef USE_VSX_EXTENSIONS
308 # define HEADER_GUARD_NAME "VSX"
309 #else
310 # define HEADER_GUARD_NAME "ALTIVEC"
311 #endif
312
313 static const char *header =
314 "/**\n"
315 " * vec - a tiny SIMD vector library in C99\n"
316 " * \n"
317 " * Copyright (c) 2024-2025 Paper\n"
318 " * \n"
319 " * Permission is hereby granted, free of charge, to any person obtaining a copy\n"
320 " * of this software and associated documentation files (the \"Software\"), to deal\n"
321 " * in the Software without restriction, including without limitation the rights\n"
322 " * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n"
323 " * copies of the Software, and to permit persons to whom the Software is\n"
324 " * furnished to do so, subject to the following conditions:\n"
325 " * \n"
326 " * The above copyright notice and this permission notice shall be included in all\n"
327 " * copies or substantial portions of the Software.\n"
328 " * \n"
329 " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n"
330 " * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n"
331 " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n"
332 " * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n"
333 " * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n"
334 " * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n"
335 " * SOFTWARE.\n"
336 "**/\n"
337 "\n"
338 "/* This file is automatically generated! Do not edit it directly!\n"
339 " * Edit the code that generates it in utils/genaltivec.c --paper */\n"
340 "\n"
341 "#ifndef VEC_IMPL_PPC_" HEADER_GUARD_NAME "_H_\n"
342 "#define VEC_IMPL_PPC_" HEADER_GUARD_NAME "_H_\n"
343 "\n";
344
345 static const char *footer =
346 "#endif /* VEC_IMPL_PPC_" HEADER_GUARD_NAME "_H_ */\n";
347
348 int main(void)
349 {
350 static struct {
351 int bits, size;
352 } defs[] = {
353 /* -- 8-bit */
354 {8, 16},
355 /* -- 16-bit */
356 {16, 8},
357
358 /* -- 32-bit */
359 {32, 4},
360
361 #ifdef USE_VSX_EXTENSIONS
362 /* -- 64-bit */
363 {64, 2},
364 #endif
365 };
366 int i;
367
368 puts(header);
369
370 for (i = 0; i < ARRAY_SIZE(defs); i++) {
371 print_ops(1, defs[i].bits, defs[i].size);
372 print_ops(0, defs[i].bits, defs[i].size);
373 }
374
375 puts(footer);
376 }