[gdb/testsuite] Fix gdb.threads/threadcrash.exp with glibc debuginfo
[binutils-gdb.git] / opcodes / loongarch-coder.c
blob575900e202349f6e59542b7efcb9494ea2103751
1 /* LoongArch opcode support.
2 Copyright (C) 2021-2024 Free Software Foundation, Inc.
3 Contributed by Loongson Ltd.
5 This file is part of the GNU opcodes library.
7 This library 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.
12 It is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; see the file COPYING3. If not,
19 see <http://www.gnu.org/licenses/>. */
20 #include "sysdep.h"
21 #include <stdbool.h>
22 #include "opcode/loongarch.h"
24 int
25 is_unsigned (const char *c_str)
27 if (c_str[0] == '0' && (c_str[1] == 'x' || c_str[1] == 'X'))
29 c_str += 2;
30 while (('a' <= *c_str && *c_str <= 'f')
31 || ('A' <= *c_str && *c_str <= 'F')
32 || ('0' <= *c_str && *c_str <= '9'))
33 c_str++;
35 else if (*c_str == '\0')
36 return 0;
37 else
38 while ('0' <= *c_str && *c_str <= '9')
39 c_str++;
40 return *c_str == '\0';
43 int
44 is_signed (const char *c_str)
46 return *c_str == '-' ? is_unsigned (c_str + 1) : is_unsigned (c_str);
49 int
50 loongarch_get_bit_field_width (const char *bit_field, char **end)
52 int width = 0;
53 char has_specify = 0, *bit_field_1 = (char *) bit_field;
54 if (bit_field_1 && *bit_field_1 != '\0')
55 while (1)
57 strtol (bit_field_1, &bit_field_1, 10);
59 if (*bit_field_1 != ':')
60 break;
61 bit_field_1++;
63 width += strtol (bit_field_1, &bit_field_1, 10);
64 has_specify = 1;
66 if (*bit_field_1 != '|')
67 break;
68 bit_field_1++;
70 if (end)
71 *end = bit_field_1;
72 return has_specify ? width : -1;
75 int32_t
76 loongarch_decode_imm (const char *bit_field, insn_t insn, int si)
78 int32_t ret = 0;
79 uint32_t t;
80 int len = 0, width, b_start;
81 char *bit_field_1 = (char *) bit_field;
82 while (1)
84 b_start = strtol (bit_field_1, &bit_field_1, 10);
85 if (*bit_field_1 != ':')
86 break;
87 width = strtol (bit_field_1 + 1, &bit_field_1, 10);
88 len += width;
90 t = insn;
91 t <<= sizeof (t) * 8 - width - b_start;
92 t >>= sizeof (t) * 8 - width;
93 ret <<= width;
94 ret |= t;
96 if (*bit_field_1 != '|')
97 break;
98 bit_field_1++;
101 if (*bit_field_1 == '<' && *(++bit_field_1) == '<')
103 width = atoi (bit_field_1 + 1);
104 ret <<= width;
105 len += width;
107 else if (*bit_field_1 == '+')
108 ret += atoi (bit_field_1 + 1);
110 /* Extend signed bit. */
111 if (si)
113 uint32_t sign = 1u << (len - 1);
114 ret = (ret ^ sign) - sign;
117 return ret;
120 static insn_t
121 loongarch_encode_imm (const char *bit_field, int32_t imm)
123 char *bit_field_1 = (char *) bit_field;
124 char *t = bit_field_1;
125 int width, b_start;
126 insn_t ret = 0;
127 uint32_t i;
128 uint32_t uimm = (uint32_t)imm;
130 width = loongarch_get_bit_field_width (t, &t);
131 if (width == -1)
132 return ret;
134 if (*t == '<' && *(++t) == '<')
135 width += atoi (t + 1);
136 else if (*t == '+')
137 uimm -= atoi (t + 1);
139 uimm = width ? (uimm << (sizeof (uimm) * 8 - width)) : 0;
141 while (1)
143 b_start = strtol (bit_field_1, &bit_field_1, 10);
144 if (*bit_field_1 != ':')
145 break;
146 width = strtol (bit_field_1 + 1, &bit_field_1, 10);
147 i = uimm;
148 i = width ? (i >> (sizeof (i) * 8 - width)) : 0;
149 i = (b_start == 32) ? 0 : (i << b_start);
150 ret |= i;
151 uimm = (width == 32) ? 0 : (uimm << width);
153 if (*bit_field_1 != '|')
154 break;
155 bit_field_1++;
157 return ret;
160 /* Parse such FORMAT
163 "v0:5,r5:5,s10:10<<2"
164 "r0:5,r5:5,r10:5,u15:2+1"
165 "r,r,u0:5+32,u0:5+1"
167 static int
168 loongarch_parse_format (const char *format, char *esc1s, char *esc2s,
169 const char **bit_fields)
171 size_t arg_num = 0;
173 if (*format == '\0')
174 goto end;
176 while (1)
178 /* esc1 esc2
179 for "[a-zA-Z][a-zA-Z]?" */
180 if (('a' <= *format && *format <= 'z')
181 || ('A' <= *format && *format <= 'Z'))
183 *esc1s++ = *format++;
184 if (('a' <= *format && *format <= 'z')
185 || ('A' <= *format && *format <= 'Z'))
186 *esc2s++ = *format++;
187 else
188 *esc2s++ = '\0';
190 else
191 return -1;
193 arg_num++;
194 if (MAX_ARG_NUM_PLUS_2 - 2 < arg_num)
195 /* Need larger MAX_ARG_NUM_PLUS_2. */
196 return -1;
198 *bit_fields++ = format;
200 if ('0' <= *format && *format <= '9')
202 /* For "[0-9]+:[0-9]+(\|[0-9]+:[0-9]+)*". */
203 while (1)
205 while ('0' <= *format && *format <= '9')
206 format++;
208 if (*format != ':')
209 return -1;
210 format++;
212 if (!('0' <= *format && *format <= '9'))
213 return -1;
214 while ('0' <= *format && *format <= '9')
215 format++;
217 if (*format != '|')
218 break;
219 format++;
222 /* For "((\+|<<)[1-9][0-9]*)?". */
225 if (*format == '+')
226 format++;
227 else if (format[0] == '<' && format[1] == '<')
228 format += 2;
229 else
230 break;
232 if (!('1' <= *format && *format <= '9'))
233 return -1;
234 while ('0' <= *format && *format <= '9')
235 format++;
237 while (0);
240 if (*format == ',')
241 format++;
242 else if (*format == '\0')
243 break;
244 else
245 return -1;
248 end:
249 *esc1s = '\0';
250 return 0;
253 size_t
254 loongarch_split_args_by_comma (char *args, const char *arg_strs[])
256 size_t num = 0;
258 if (*args)
260 bool inquote = false;
261 arg_strs[num++] = args;
262 for (; *args; args++)
263 if (*args == '"')
264 inquote = !inquote;
265 else if (*args == ',' && !inquote)
267 if (MAX_ARG_NUM_PLUS_2 - 1 == num)
268 goto out;
269 *args = '\0';
270 arg_strs[num++] = args + 1;
273 if (*(args - 1) == '"' && *arg_strs[num - 1] == '"')
275 *(args - 1) = '\0';
276 arg_strs[num - 1] += 1;
279 out:
280 arg_strs[num] = NULL;
281 return num;
284 char *
285 loongarch_cat_splited_strs (const char *arg_strs[])
287 char *ret;
288 size_t n, l;
290 for (l = 0, n = 0; arg_strs[n]; n++)
291 l += strlen (arg_strs[n]);
292 ret = malloc (l + n + 1);
293 if (!ret)
294 return ret;
296 ret[0] = '\0';
297 if (0 < n)
298 strcat (ret, arg_strs[0]);
299 for (l = 1; l < n; l++)
300 strcat (ret, ","), strcat (ret, arg_strs[l]);
301 return ret;
304 insn_t
305 loongarch_foreach_args (const char *format, const char *arg_strs[],
306 int32_t (*helper) (char esc1, char esc2,
307 const char *bit_field,
308 const char *arg, void *context),
309 void *context)
311 char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1];
312 const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1];
313 size_t i;
314 insn_t ret = 0;
315 int ok;
317 ok = loongarch_parse_format (format, esc1s, esc2s, bit_fields) == 0;
319 /* Make sure the num of actual args is equal to the num of escape. */
320 for (i = 0; esc1s[i] && arg_strs[i]; i++)
322 ok = ok && !esc1s[i] && !arg_strs[i];
324 if (ok && helper)
326 for (i = 0; arg_strs[i]; i++)
327 ret |= loongarch_encode_imm (bit_fields[i],
328 helper (esc1s[i], esc2s[i],
329 bit_fields[i], arg_strs[i],
330 context));
331 ret |= helper ('\0', '\0', NULL, NULL, context);
334 return ret;
338 loongarch_check_format (const char *format)
340 char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1];
341 const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1];
343 if (!format)
344 return -1;
346 return loongarch_parse_format (format, esc1s, esc2s, bit_fields);
350 loongarch_check_macro (const char *format, const char *macro)
352 int num_of_args;
353 char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1];
354 const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1];
356 if (!format || !macro
357 || loongarch_parse_format (format, esc1s, esc2s, bit_fields) != 0)
358 return -1;
360 for (num_of_args = 0; esc1s[num_of_args]; num_of_args++)
363 for (; macro[0]; macro++)
364 if (macro[0] == '%')
366 macro++;
367 if ('1' <= macro[0] && macro[0] <= '9')
369 if (num_of_args < macro[0] - '0')
370 /* Out of args num. */
371 return -1;
373 else if (macro[0] == 'f')
375 else if (macro[0] == '%')
377 else
378 return -1;
380 return 0;
383 static const char *
384 I (char esc_ch1 ATTRIBUTE_UNUSED, char esc_ch2 ATTRIBUTE_UNUSED,
385 const char *c_str)
387 return c_str;
390 char *
391 loongarch_expand_macro_with_format_map (
392 const char *format, const char *macro, const char *const arg_strs[],
393 const char *(*map) (char esc1, char esc2, const char *arg),
394 char *(*helper) (const char *const arg_strs[], void *context), void *context,
395 size_t len_str)
397 char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1];
398 const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1];
399 const char *src;
400 char *dest;
402 /* The expanded macro character length does not exceed 1000, and number of
403 label is 6 at most in the expanded macro. The len_str is the length of
404 str. */
405 char *buffer =(char *) malloc(1024 + 6 * len_str);
407 if (format)
408 loongarch_parse_format (format, esc1s, esc2s, bit_fields);
410 src = macro;
411 dest = buffer;
413 while (*src)
414 if (*src == '%')
416 src++;
417 if ('1' <= *src && *src <= '9')
419 size_t i = *src - '1';
420 const char *t = map (esc1s[i], esc2s[i], arg_strs[i]);
421 while (*t)
422 *dest++ = *t++;
424 else if (*src == '%')
425 *dest++ = '%';
426 else if (*src == 'f' && helper)
428 char *b, *t;
429 t = b = (*helper) (arg_strs, context);
430 if (b)
432 while (*t)
433 *dest++ = *t++;
434 free (b);
437 src++;
439 else
440 *dest++ = *src++;
442 *dest = '\0';
443 return buffer;
446 char *
447 loongarch_expand_macro (const char *macro, const char *const arg_strs[],
448 char *(*helper) (const char *const arg_strs[],
449 void *context),
450 void *context, size_t len_str)
452 return loongarch_expand_macro_with_format_map (NULL, macro, arg_strs, I,
453 helper, context, len_str);
456 size_t
457 loongarch_bits_imm_needed (int64_t imm, int si)
459 size_t ret;
460 if (si)
462 if (imm < 0)
464 uint64_t uimm = (uint64_t) imm;
465 uint64_t uimax = UINT64_C (1) << 63;
466 for (ret = 0; (uimm & uimax) != 0; uimm <<= 1, ret++)
468 ret = 64 - ret + 1;
470 else
471 ret = loongarch_bits_imm_needed (imm, 0) + 1;
473 else
475 uint64_t t = imm;
476 for (ret = 0; t; t >>= 1, ret++)
479 return ret;
482 void
483 loongarch_eliminate_adjacent_repeat_char (char *dest, char c)
485 if (c == '\0')
486 return;
487 char *src = dest;
488 while (*dest)
490 while (src[0] == c && src[0] == src[1])
491 src++;
492 *dest++ = *src++;