comparison gen/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
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 #include "genlib.h"
26
27 #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
28
29 /* ------------------------------------------------------------------------ */
30
31 /* #define USE_VSX_EXTENSIONS */
32 /* #define USE_POWER8_EXTENSIONS */
33
34 static int altivec_check(int op, int type, int bits, int size)
35 {
36 switch (bits) {
37 case 8:
38 case 16:
39 case 32:
40 #ifdef USE_VSX_EXTENSIONS
41 case 64:
42 # ifndef USE_POWER8_EXTENSIONS
43 /* VSX has double, but not int64 */
44 if ((bits == 64) && (type != TYPE_FLOAT))
45 return 0;
46 # endif
47 #endif
48 if (bits * size == 128)
49 return 1;
50 default:
51 break;
52 }
53
54 return 0;
55 }
56
57 static int altivec_check_int(int op, int type, int bits, int size)
58 {
59 return (altivec_check(op, type, bits, size) && type != TYPE_FLOAT);
60 }
61
62 static int altivec_check_float(int op, int type, int bits, int size)
63 {
64 return (altivec_check(op, type, bits, size) && type == TYPE_FLOAT);
65 }
66
67 static void altivec_ppcheck(int op, int type, int bits, int size)
68 {
69 /* old gcc had a broken partial implementation
70 * (why even bother adding it at all?) */
71 switch (op) {
72 case OP_MUL: printf("defined(vec_mul)"); break;
73 case OP_SPLAT: printf("defined(vec_splats)"); break;
74 }
75 }
76
77 static void altivec_splat(int op, int type, int bits, int size)
78 {
79 printf("\t");
80 gen_print_vtype(type, bits, size);
81 printf(" vec;\n");
82
83 puts("\tvec.altivec = vec_splats(x);");
84 puts("\treturn vec;");
85 }
86
87 static void altivec_load(int op, int type, int bits, int size)
88 {
89 printf("\t");
90 gen_print_vtype(type, bits, size);
91 printf(" vec;\n");
92
93 puts("\tvec.altivec = vec_perm(vec_ld(0, x), vec_ld(16, x), vec_lvsl(0, x));");
94 puts("\treturn vec;");
95 }
96
97 static void altivec_load_aligned(int op, int type, int bits, int size)
98 {
99 printf("\t");
100 gen_print_vtype(type, bits, size);
101 printf(" vec;\n");
102
103 puts("\tvec.altivec = vec_ld(0, x);");
104 puts("\treturn vec;");
105 }
106
107 static void altivec_store_aligned(int op, int type, int bits, int size)
108 {
109 puts("\tvec_st(vec.altivec, 0, x);");
110 }
111
112 /* no store? */
113
114 static void altivec_print_native_type(int type, int bits)
115 {
116 /* WITH DIRECTION AND MAGNITUDE! */
117 printf("vector ");
118
119 switch (type) {
120 case TYPE_INT:
121 printf("signed ");
122 break;
123 case TYPE_UINT:
124 printf("unsigned ");
125 break;
126 case TYPE_FLOAT:
127 /* nothing */
128 break;
129 }
130
131 switch (type) {
132 case TYPE_INT:
133 case TYPE_UINT:
134 switch (bits) {
135 case 8: printf("char"); break;
136 case 16: printf("short"); break;
137 case 32: printf("int"); break;
138 case 64: printf("long long"); break;
139 default: break;
140 }
141 break;
142 case TYPE_FLOAT:
143 switch (bits) {
144 case 32: printf("float"); break;
145 case 64: printf("double"); break;
146 default: break;
147 }
148 }
149 }
150
151 static void altivec_2op(int op, int type, int bits, int size)
152 {
153 static const char *op_altivec[] = {
154 [OP_ADD] = "add",
155 [OP_SUB] = "sub",
156 [OP_MUL] = "mul",
157 [OP_DIV] = "div",
158 [OP_MOD] = "mod",
159 [OP_AND] = "and",
160 [OP_OR] = "or",
161 [OP_XOR] = "xor",
162 [OP_CMPLT] = "cmplt",
163 [OP_CMPEQ] = "cmpeq",
164 [OP_CMPGT] = "cmpgt",
165 [OP_CMPLE] = "cmple",
166 [OP_CMPGE] = "cmpge",
167 [OP_MIN] = "min",
168 [OP_MAX] = "max",
169 [OP_AVG] = "avg",
170 [OP_LSHIFT] = "sl",
171 [OP_LRSHIFT] = "sr",
172 };
173
174 printf("\t");
175 gen_print_vtype(type, bits, size);
176 printf(" vec;\n");
177
178 if (op == OP_RSHIFT) {
179 printf("\tvec.altivec = vec_sr%s(vec1.altivec, vec2.altivec);\n", (type == TYPE_INT) ? "a" : "");
180 } else {
181 printf("\tvec.altivec = (");
182 altivec_print_native_type(type, bits);
183 printf(")vec_%s(vec1.altivec, vec2.altivec);\n", op_altivec[op]);
184 }
185
186 puts("\treturn vec;");
187 }
188
189 /* ------------------------------------------------------------------------ */
190
191 static struct op_impl op_impl[OP_FINAL_] = {
192 [OP_SPLAT] = {altivec_check, NULL, altivec_splat},
193 [OP_LOAD_ALIGNED] = {altivec_check, NULL, altivec_load_aligned},
194 [OP_LOAD] = {altivec_check, NULL, altivec_load},
195 [OP_STORE_ALIGNED] = {altivec_check, NULL, altivec_store_aligned},
196
197 /* arithmetic */
198 [OP_ADD] = {altivec_check, NULL, altivec_2op},
199 [OP_SUB] = {altivec_check, NULL, altivec_2op},
200 [OP_MUL] = {altivec_check, NULL, altivec_2op},
201 #ifdef USE_VSX_EXTENSIONS
202 /* GCC fails to compile integer division, so limit to floats */
203 [OP_DIV] = {altivec_check_float, NULL, altivec_2op},
204 #endif
205 #if 0
206 /* This is Power10. I don't have any Power10 hardware :)
207 * (well, I also don't have any VSX hardware. whatever) */
208 [OP_MOD] = {altivec_check_int, NULL, altivec_2op},
209 #endif
210 [OP_AVG] = {altivec_check_int, NULL, altivec_2op},
211
212 /* bitwise */
213 [OP_AND] = {altivec_check, NULL, altivec_2op},
214 [OP_OR] = {altivec_check, NULL, altivec_2op},
215 [OP_XOR] = {altivec_check, NULL, altivec_2op},
216
217 /* min/max */
218 [OP_MIN] = {altivec_check, NULL, altivec_2op},
219 [OP_MAX] = {altivec_check, NULL, altivec_2op},
220
221 /* bitshift */
222 [OP_LSHIFT] = {altivec_check, NULL, altivec_2op},
223 [OP_LRSHIFT] = {altivec_check, NULL, altivec_2op},
224 [OP_RSHIFT] = {altivec_check, NULL, altivec_2op},
225
226 /* comparison */
227 [OP_CMPLT] = {altivec_check, NULL, altivec_2op},
228 #ifdef USE_VSX_EXTENSIONS
229 [OP_CMPLE] = {altivec_check, NULL, altivec_2op},
230 #endif
231 [OP_CMPEQ] = {altivec_check, NULL, altivec_2op},
232 #ifdef USE_VSX_EXTENSIONS
233 [OP_CMPGE] = {altivec_check, NULL, altivec_2op},
234 #endif
235 [OP_CMPGT] = {altivec_check, NULL, altivec_2op},
236 };
237
238
239 int main(void)
240 {
241 gen(op_impl,
242 #ifdef USE_POWER8_EXTENSIONS
243 "power8"
244 #elif defined(USE_VSX_EXTENSIONS)
245 "vsx"
246 #else
247 "altivec"
248 #endif
249 );
250 }