ee5acd4eb4fc36c3c53c9efc899d7a37e6f28070
[binutils-gdb.git] / gas / config / tc-ppc-svp64.c
1 /* tc-ppc-svp64.c -- Assemble for the PowerPC SVP64 extension.
2 Copyright (C) 2022 Free Software Foundation, Inc.
3 Written by Dmitry Selyutin aka ghostmansd.
4
5 This file is part of GAS, the GNU Assembler.
6
7 GAS is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GAS is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GAS; see the file COPYING. If not, write to the Free
19 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
20 02110-1301, USA. */
21
22 #include <setjmp.h>
23
24 struct svp64_ctx {
25 const struct svp64_desc *desc;
26 unsigned int pmmode : 1;
27 unsigned int pmask : 3;
28 unsigned int smmode : 1;
29 unsigned int smask : 3;
30 unsigned int mmode : 1;
31 unsigned int has_pmask : 1;
32 unsigned int has_smask : 1;
33 unsigned int mask_m_specified : 1;
34 unsigned int subvl : 2;
35 unsigned int destwid : 2;
36 unsigned int srcwid : 2;
37 unsigned int ldst_elstride : 1;
38 unsigned int sv_mode_explicit : 1;
39 unsigned int sv_mode : 2;
40 unsigned int sat : 1;
41 unsigned int src_zero : 1;
42 unsigned int dst_zero : 1;
43 unsigned int ff : 3 + 2; /* 3-bit plus RC1 */
44 unsigned int pr : 3 + 2; /* 3-bit plus RC1 */
45 };
46
47 #define SVP64_RC1_ACTIVE (1U << 3U)
48 #define SVP64_RC1_INVERT (SVP64_RC1_ACTIVE | (1U << 4U))
49
50 static jmp_buf svp64_exception;
51
52 #define svp64_raise(...) \
53 do { \
54 as_bad (__VA_ARGS__); \
55 longjmp (svp64_exception, 1); \
56 } while (0)
57
58 #define svp64_raise_if(COND, ...) \
59 do { \
60 if (!!(COND)) \
61 svp64_raise (__VA_ARGS__); \
62 } while (0)
63
64 static htab_t svp64_hash;
65
66 static void
67 svp64_setup_records (void)
68 {
69 const struct svp64_record *record;
70 const struct svp64_record *records_end;
71
72 svp64_hash = str_htab_create ();
73
74 records_end = (svp64_records + svp64_nr_records);
75 for (record = svp64_records; record < records_end; ++record)
76 {
77 const struct svp64_desc *desc = &record->desc;
78 const char *name = (record->name + (sizeof ("sv.") - 1));
79
80 if (str_hash_insert (svp64_hash, name, desc, 0) != NULL)
81 as_fatal (_("duplicate %s"), name);
82 }
83 }
84
85 #define SVP64_SEP '/'
86
87 struct svp64_predicate_map {
88 const char *str;
89 unsigned int len : 3;
90 unsigned int cr : 1;
91 unsigned int mask : 3 + 2; /* 3-bit plus RC1 */
92 };
93 #define SVP64_PREDICATE_MAP(STR, MODE, MASK) \
94 { STR, (sizeof (STR) - 1), MODE, MASK }
95
96 static char *
97 svp64_decode_predicate (char *str, bool *cr, unsigned int *mask)
98 {
99 size_t i;
100 static const struct svp64_predicate_map table[] = {
101 /* integer */
102 SVP64_PREDICATE_MAP ("1<<r3", 0, 1),
103 SVP64_PREDICATE_MAP ("r3" , 0, 2),
104 SVP64_PREDICATE_MAP ("~r3" , 0, 3),
105 SVP64_PREDICATE_MAP ("r10" , 0, 4),
106 SVP64_PREDICATE_MAP ("~r10" , 0, 5),
107 SVP64_PREDICATE_MAP ("r30" , 0, 6),
108 SVP64_PREDICATE_MAP ("~r30" , 0, 7),
109 /* CR */
110 SVP64_PREDICATE_MAP ("lt" , 1, 0),
111 SVP64_PREDICATE_MAP ("nl" , 1, 1),
112 SVP64_PREDICATE_MAP ("ge" , 1, 1), /* same value as nl */
113 SVP64_PREDICATE_MAP ("gt" , 1, 2),
114 SVP64_PREDICATE_MAP ("ng" , 1, 3),
115 SVP64_PREDICATE_MAP ("le" , 1, 3), /* same value as ng */
116 SVP64_PREDICATE_MAP ("eq" , 1, 4),
117 SVP64_PREDICATE_MAP ("ne" , 1, 5),
118 SVP64_PREDICATE_MAP ("so" , 1, 6),
119 SVP64_PREDICATE_MAP ("un" , 1, 6), /* same value as so */
120 SVP64_PREDICATE_MAP ("ns" , 1, 7),
121 SVP64_PREDICATE_MAP ("nu" , 1, 7), /* same value as ns */
122 /* RC1 */
123 SVP64_PREDICATE_MAP ("RC1" , 0, SVP64_RC1_ACTIVE),
124 SVP64_PREDICATE_MAP ("~RC1" , 0, SVP64_RC1_INVERT),
125 };
126
127 for (i = 0; i < sizeof (table) / sizeof (table[0]); ++i)
128 {
129 const struct svp64_predicate_map *entry = &table[i];
130
131 if (strncmp (str, entry->str, entry->len) != 0)
132 continue;
133
134 str += entry->len;
135 if (! ISSPACE (*str) && *str != SVP64_SEP && *str != '\0')
136 {
137 str -= entry->len;
138 continue;
139 }
140
141 *mask = entry->mask;
142 *cr = entry->cr;
143
144 *str++ = '\0';
145
146 return str;
147 }
148
149 return NULL;
150 }
151
152 struct svp64_decoder {
153 char *(*call)(char *str, struct svp64_ctx *svp64);
154 const char *str;
155 size_t len;
156 };
157 #define SVP64_DECODER(STR, CALL) \
158 { CALL, STR, (sizeof (STR) - 1) }
159
160 static char *
161 svp64_decode_m (char *str, struct svp64_ctx *svp64)
162 {
163 char *iter;
164 bool cr;
165 unsigned int pmmode;
166 unsigned int pmask;
167
168 str += (sizeof ("m=") - 1);
169 iter = svp64_decode_predicate (str, &cr, &pmask);
170 if (!iter || ((pmask & SVP64_RC1_ACTIVE) != 0))
171 svp64_raise (_("unrecognized mode: `%s'"), str);
172
173 pmmode = (cr ? 1 : 0);
174 svp64->pmmode = pmmode;
175 svp64->pmask = pmask;
176 svp64->smmode = pmmode;
177 svp64->smask = pmask;
178 svp64->mmode = pmmode;
179 svp64->mask_m_specified = 1;
180
181 return iter;
182 }
183
184 static char *
185 svp64_decode_dm (char *str, struct svp64_ctx *svp64)
186 {
187 char *iter;
188 bool cr;
189 unsigned int pmmode;
190 unsigned int pmask;
191
192 str += (sizeof ("dm=") - 1);
193 iter = svp64_decode_predicate (str, &cr, &pmask);
194 if (!iter || ((pmask & SVP64_RC1_ACTIVE) != 0))
195 svp64_raise (_("unrecognized mode: `%s'"), str);
196
197 pmmode = (cr ? 1 : 0);
198 svp64->pmmode = pmmode;
199 svp64->pmask = pmask;
200 svp64->mmode = pmmode;
201 svp64->has_pmask = 1;
202
203 return iter;
204 }
205
206 static char *
207 svp64_decode_sm (char *str, struct svp64_ctx *svp64)
208 {
209 char *iter;
210 bool cr;
211 unsigned int smmode;
212 unsigned int smask;
213
214 str += (sizeof ("sm=") - 1);
215 iter = svp64_decode_predicate (str, &cr, &smask);
216 if (!iter || ((smask & SVP64_RC1_ACTIVE) != 0))
217 svp64_raise (_("unrecognized mode: `%s'"), str);
218
219 smmode = (cr ? 1 : 0);
220 svp64->smmode = smmode;
221 svp64->smask = smask;
222 svp64->mmode = smmode;
223 svp64->has_smask = 1;
224
225 return iter;
226 }
227
228 static char *
229 svp64_decode_vec (char *str, struct svp64_ctx *svp64)
230 {
231 char *subvl;
232
233 str += (sizeof ("vec") - 1);
234 if ( ISSPACE (*str) || *str == SVP64_SEP || *str == '\0')
235 return NULL;
236
237 subvl = str++;
238 if ( ! ISSPACE (*str) && *str != SVP64_SEP && *str != '\0')
239 return NULL;
240
241 switch (*subvl)
242 {
243 case '2':
244 svp64->subvl = 1;
245 break;
246 case '3':
247 svp64->subvl = 2;
248 break;
249 case '4':
250 svp64->subvl = 3;
251 break;
252 default:
253 return NULL;
254 }
255
256 *str++ = '\0';
257
258 return str;
259 }
260
261 struct svp64_width_map {
262 const char *str;
263 unsigned int len;
264 unsigned int width;
265 };
266 #define SVP64_WIDTH_MAP(STR, WIDTH) \
267 { STR, (sizeof (STR) - 1), WIDTH }
268
269 static char *
270 svp64_decode_width (char *str, unsigned int *width)
271 {
272 size_t i;
273 static const struct svp64_width_map table[] = {
274 SVP64_WIDTH_MAP ("8", 3),
275 SVP64_WIDTH_MAP ("16", 2),
276 SVP64_WIDTH_MAP ("32", 1),
277 };
278
279 for (i = 0; i < (sizeof (table) / sizeof (table[0])); ++i)
280 {
281 const struct svp64_width_map *entry = &table[i];
282
283 if (strncmp (str, entry->str, entry->len) != 0)
284 continue;
285
286 str += entry->len;
287 if (! ISSPACE (*str) && *str != SVP64_SEP && *str != '\0')
288 {
289 str -= entry->len;
290 continue;
291 }
292
293 *width = entry->width;
294
295 *str++ = '\0';
296
297 return str;
298 }
299
300 return NULL;
301 }
302
303 static char *
304 svp64_decode_w (char *str, struct svp64_ctx *svp64)
305 {
306 char *iter;
307 unsigned int width;
308
309 str += (sizeof ("w=") - 1);
310 iter = svp64_decode_width (str, &width);
311 if (!iter)
312 svp64_raise (_("unrecognized mode: `%s'"), str);
313
314 svp64->srcwid = width;
315 svp64->destwid = width;
316
317 return iter;
318 }
319
320 static char *
321 svp64_decode_dw (char *str, struct svp64_ctx *svp64)
322 {
323 char *iter;
324 unsigned int width;
325
326 str += (sizeof ("dw=") - 1);
327 iter = svp64_decode_width (str, &width);
328 if (!iter)
329 svp64_raise (_("unrecognized mode: `%s'"), str);
330
331 svp64->destwid = width;
332
333 return iter;
334 }
335
336 static char *
337 svp64_decode_sw (char *str, struct svp64_ctx *svp64)
338 {
339 char *iter;
340 unsigned int width;
341
342 str += (sizeof ("sw=") - 1);
343 iter = svp64_decode_width (str, &width);
344 if (!iter)
345 svp64_raise (_("unrecognized mode: `%s'"), str);
346
347 svp64->srcwid = width;
348
349 return iter;
350 }
351
352 static char *
353 svp64_decode_els (char *str, struct svp64_ctx *svp64)
354 {
355 str += (sizeof ("els") - 1);
356 if ( ! ISSPACE (*str) && *str != SVP64_SEP && *str != '\0')
357 return NULL;
358
359 svp64->ldst_elstride = 1;
360
361 *str++ = '\0';
362
363 return str;
364 }
365
366 static char *
367 svp64_decode_sat (char *str, struct svp64_ctx *svp64)
368 {
369 unsigned char mode;
370
371 str += (sizeof ("sat") - 1);
372 if ((*str != 's') && (*str != 'u'))
373 return NULL;
374
375 mode = *str++;
376 if ( ! ISSPACE (*str) && *str != SVP64_SEP && *str != '\0')
377 return NULL;
378
379 if (svp64->sv_mode_explicit)
380 svp64_raise (_("SV mode conflict: `%s'"), str);
381
382 svp64->sv_mode_explicit = 1;
383 svp64->sv_mode = 2;
384 svp64->sat = (mode == 's');
385
386 *str++ = '\0';
387
388 return str;
389 }
390
391 static char *
392 svp64_decode_sz (char *str, struct svp64_ctx *svp64)
393 {
394 str += (sizeof ("sz") - 1);
395 if ( ! ISSPACE (*str) && *str != SVP64_SEP && *str != '\0')
396 return NULL;
397
398 svp64->src_zero = 1;
399
400 *str++ = '\0';
401
402 return str;
403 }
404
405 static char *
406 svp64_decode_dz (char *str, struct svp64_ctx *svp64)
407 {
408 str += (sizeof ("dz") - 1);
409 if ( ! ISSPACE (*str) && *str != SVP64_SEP && *str != '\0')
410 return NULL;
411
412 svp64->dst_zero = 1;
413
414 *str++ = '\0';
415
416 return str;
417 }
418
419 static char *
420 svp64_decode_ff (char *str, struct svp64_ctx *svp64)
421 {
422 char *iter;
423 bool cr;
424 unsigned int mask;
425
426 str += (sizeof ("ff=") - 1);
427 if (svp64->sv_mode_explicit)
428 svp64_raise (_("SV mode conflict: `%s'"), str);
429
430 iter = svp64_decode_predicate (str, &cr, &mask);
431 if (!iter || !(cr || ((mask & SVP64_RC1_ACTIVE) != 0)))
432 svp64_raise (_("unrecognized mode: `%s'"), str);
433
434 svp64->sv_mode_explicit = 1;
435 svp64->sv_mode = 0x1;
436 svp64->ff = mask;
437
438 return iter;
439 }
440
441 static char *
442 svp64_decode_pr (char *str, struct svp64_ctx *svp64)
443 {
444 char *iter;
445 bool cr;
446 unsigned int mask;
447
448 str += (sizeof ("pr=") - 1);
449 if (svp64->sv_mode_explicit)
450 svp64_raise (_("SV mode conflict: `%s'"), str);
451
452 iter = svp64_decode_predicate (str, &cr, &mask);
453 if (!iter || !(cr || ((mask & SVP64_RC1_ACTIVE) != 0)))
454 svp64_raise (_("unrecognized mode: `%s'"), str);
455
456 svp64->sv_mode_explicit = 1;
457 svp64->sv_mode = 0x3;
458 svp64->pr = mask;
459
460 return iter;
461 }
462
463 static char *
464 svp64_decode_mode (char *str, struct svp64_ctx *svp64)
465 {
466 size_t i;
467 static const struct svp64_decoder table[] = {
468 SVP64_DECODER ("m=" , svp64_decode_m),
469 SVP64_DECODER ("dm=" , svp64_decode_dm),
470 SVP64_DECODER ("sm=" , svp64_decode_sm),
471 SVP64_DECODER ("vec2", svp64_decode_vec),
472 SVP64_DECODER ("vec3", svp64_decode_vec),
473 SVP64_DECODER ("vec4", svp64_decode_vec),
474 SVP64_DECODER ("w=" , svp64_decode_w),
475 SVP64_DECODER ("dw=" , svp64_decode_dw),
476 SVP64_DECODER ("sw=" , svp64_decode_sw),
477 SVP64_DECODER ("els" , svp64_decode_els),
478 SVP64_DECODER ("sats", svp64_decode_sat),
479 SVP64_DECODER ("satu", svp64_decode_sat),
480 SVP64_DECODER ("sz" , svp64_decode_sz),
481 SVP64_DECODER ("dz" , svp64_decode_dz),
482 SVP64_DECODER ("ff=" , svp64_decode_ff),
483 SVP64_DECODER ("pr=" , svp64_decode_pr),
484 };
485
486 for (i = 0; i < sizeof (table) / sizeof (table[0]); ++i)
487 {
488 const struct svp64_decoder *entry = &table[i];
489
490 if (strncmp (str, entry->str, entry->len) == 0)
491 return entry->call (str, svp64);
492 }
493
494 return NULL;
495 }
496
497 static void
498 svp64_decode (char *str, struct svp64_ctx *svp64)
499 {
500 char *opc;
501 char *iter;
502
503 str += (sizeof ("sv.") - 1);
504 if (! ISALPHA (*str))
505 svp64_raise (_("unrecognized opcode: `%s'"), str);
506
507 opc = str;
508 for (; ! ISSPACE (*str) && *str != SVP64_SEP && *str != '\0'; ++str)
509 ;
510 if (*str != '\0')
511 *str++ = '\0';
512
513 for (; (iter = svp64_decode_mode (str, svp64)) != NULL; str = iter)
514 ;
515
516 svp64->desc = (const struct svp64_desc *) str_hash_find (svp64_hash, opc);
517 if (!svp64->desc)
518 svp64_raise (_("unrecognized opcode: `%s'"), str);
519 }
520
521 static void
522 svp64_assemble (char *str)
523 {
524 struct svp64_ctx svp64;
525
526 if (setjmp (svp64_exception) != 0)
527 return;
528
529 memset (&svp64, 0, sizeof (svp64));
530
531 svp64_decode (str, &svp64);
532
533 as_warn (_("opcode ignored (desc=%p)"), svp64.desc);
534 memcpy (str, "nop", sizeof ("nop"));
535 md_assemble (str);
536 }