]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - opcodes/loongarch-coder.c
LoongArch: Add support for <b ".L1"> and <beq, $t0, $t1, ".L1">
[thirdparty/binutils-gdb.git] / opcodes / loongarch-coder.c
1 /* LoongArch opcode support.
2 Copyright (C) 2021-2023 Free Software Foundation, Inc.
3 Contributed by Loongson Ltd.
4
5 This file is part of the GNU opcodes library.
6
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.
11
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.
16
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 "opcode/loongarch.h"
22
23 int
24 is_unsigned (const char *c_str)
25 {
26 if (c_str[0] == '0' && (c_str[1] == 'x' || c_str[1] == 'X'))
27 {
28 c_str += 2;
29 while (('a' <= *c_str && *c_str <= 'f')
30 || ('A' <= *c_str && *c_str <= 'F')
31 || ('0' <= *c_str && *c_str <= '9'))
32 c_str++;
33 }
34 else if (*c_str == '\0')
35 return 0;
36 else
37 while ('0' <= *c_str && *c_str <= '9')
38 c_str++;
39 return *c_str == '\0';
40 }
41
42 int
43 is_signed (const char *c_str)
44 {
45 return *c_str == '-' ? is_unsigned (c_str + 1) : is_unsigned (c_str);
46 }
47
48 int
49 loongarch_get_bit_field_width (const char *bit_field, char **end)
50 {
51 int width = 0;
52 char has_specify = 0, *bit_field_1 = (char *) bit_field;
53 if (bit_field_1 && *bit_field_1 != '\0')
54 while (1)
55 {
56 strtol (bit_field_1, &bit_field_1, 10);
57
58 if (*bit_field_1 != ':')
59 break;
60 bit_field_1++;
61
62 width += strtol (bit_field_1, &bit_field_1, 10);
63 has_specify = 1;
64
65 if (*bit_field_1 != '|')
66 break;
67 bit_field_1++;
68 }
69 if (end)
70 *end = bit_field_1;
71 return has_specify ? width : -1;
72 }
73
74 int32_t
75 loongarch_decode_imm (const char *bit_field, insn_t insn, int si)
76 {
77 int32_t ret = 0;
78 uint32_t t;
79 int len = 0, width, b_start;
80 char *bit_field_1 = (char *) bit_field;
81 while (1)
82 {
83 b_start = strtol (bit_field_1, &bit_field_1, 10);
84 if (*bit_field_1 != ':')
85 break;
86 width = strtol (bit_field_1 + 1, &bit_field_1, 10);
87 len += width;
88
89 t = insn;
90 t <<= sizeof (t) * 8 - width - b_start;
91 t >>= sizeof (t) * 8 - width;
92 ret <<= width;
93 ret |= t;
94
95 if (*bit_field_1 != '|')
96 break;
97 bit_field_1++;
98 }
99
100 if (*bit_field_1 == '<' && *(++bit_field_1) == '<')
101 {
102 width = atoi (bit_field_1 + 1);
103 ret <<= width;
104 len += width;
105 }
106 else if (*bit_field_1 == '+')
107 ret += atoi (bit_field_1 + 1);
108
109 /* Extend signed bit. */
110 if (si)
111 {
112 uint32_t sign = 1u << (len - 1);
113 ret = (ret ^ sign) - sign;
114 }
115
116 return ret;
117 }
118
119 static insn_t
120 loongarch_encode_imm (const char *bit_field, int32_t imm)
121 {
122 char *bit_field_1 = (char *) bit_field;
123 char *t = bit_field_1;
124 int width, b_start;
125 insn_t ret = 0;
126 uint32_t i;
127 uint32_t uimm = (uint32_t)imm;
128
129 width = loongarch_get_bit_field_width (t, &t);
130 if (width == -1)
131 return ret;
132
133 if (*t == '<' && *(++t) == '<')
134 width += atoi (t + 1);
135 else if (*t == '+')
136 uimm -= atoi (t + 1);
137
138 uimm = width ? (uimm << (sizeof (uimm) * 8 - width)) : 0;
139
140 while (1)
141 {
142 b_start = strtol (bit_field_1, &bit_field_1, 10);
143 if (*bit_field_1 != ':')
144 break;
145 width = strtol (bit_field_1 + 1, &bit_field_1, 10);
146 i = uimm;
147 i = width ? (i >> (sizeof (i) * 8 - width)) : 0;
148 i = (b_start == 32) ? 0 : (i << b_start);
149 ret |= i;
150 uimm = (width == 32) ? 0 : (uimm << width);
151
152 if (*bit_field_1 != '|')
153 break;
154 bit_field_1++;
155 }
156 return ret;
157 }
158
159 /* Parse such FORMAT
160 ""
161 "u"
162 "v0:5,r5:5,s10:10<<2"
163 "r0:5,r5:5,r10:5,u15:2+1"
164 "r,r,u0:5+32,u0:5+1"
165 */
166 static int
167 loongarch_parse_format (const char *format, char *esc1s, char *esc2s,
168 const char **bit_fields)
169 {
170 size_t arg_num = 0;
171
172 if (*format == '\0')
173 goto end;
174
175 while (1)
176 {
177 /* esc1 esc2
178 for "[a-zA-Z][a-zA-Z]?" */
179 if (('a' <= *format && *format <= 'z')
180 || ('A' <= *format && *format <= 'Z'))
181 {
182 *esc1s++ = *format++;
183 if (('a' <= *format && *format <= 'z')
184 || ('A' <= *format && *format <= 'Z'))
185 *esc2s++ = *format++;
186 else
187 *esc2s++ = '\0';
188 }
189 else
190 return -1;
191
192 arg_num++;
193 if (MAX_ARG_NUM_PLUS_2 - 2 < arg_num)
194 /* Need larger MAX_ARG_NUM_PLUS_2. */
195 return -1;
196
197 *bit_fields++ = format;
198
199 if ('0' <= *format && *format <= '9')
200 {
201 /* For "[0-9]+:[0-9]+(\|[0-9]+:[0-9]+)*". */
202 while (1)
203 {
204 while ('0' <= *format && *format <= '9')
205 format++;
206
207 if (*format != ':')
208 return -1;
209 format++;
210
211 if (!('0' <= *format && *format <= '9'))
212 return -1;
213 while ('0' <= *format && *format <= '9')
214 format++;
215
216 if (*format != '|')
217 break;
218 format++;
219 }
220
221 /* For "((\+|<<)[1-9][0-9]*)?". */
222 do
223 {
224 if (*format == '+')
225 format++;
226 else if (format[0] == '<' && format[1] == '<')
227 format += 2;
228 else
229 break;
230
231 if (!('1' <= *format && *format <= '9'))
232 return -1;
233 while ('0' <= *format && *format <= '9')
234 format++;
235 }
236 while (0);
237 }
238
239 if (*format == ',')
240 format++;
241 else if (*format == '\0')
242 break;
243 else
244 return -1;
245 }
246
247 end:
248 *esc1s = '\0';
249 return 0;
250 }
251
252 size_t
253 loongarch_split_args_by_comma (char *args, const char *arg_strs[])
254 {
255 size_t num = 0;
256
257 if (*args)
258 arg_strs[num++] = args;
259 for (; *args; args++)
260 if (*args == ',')
261 {
262 if (MAX_ARG_NUM_PLUS_2 - 1 == num)
263 break;
264 else
265 *args = '\0', arg_strs[num++] = args + 1;
266 }
267
268 if (*(args-1) == '"')
269 {
270 *(args-1) = '\0';
271 arg_strs[num-1] = arg_strs[num-1] + 1;
272 }
273
274 arg_strs[num] = NULL;
275 return num;
276 }
277
278 char *
279 loongarch_cat_splited_strs (const char *arg_strs[])
280 {
281 char *ret;
282 size_t n, l;
283
284 for (l = 0, n = 0; arg_strs[n]; n++)
285 l += strlen (arg_strs[n]);
286 ret = malloc (l + n + 1);
287 if (!ret)
288 return ret;
289
290 ret[0] = '\0';
291 if (0 < n)
292 strcat (ret, arg_strs[0]);
293 for (l = 1; l < n; l++)
294 strcat (ret, ","), strcat (ret, arg_strs[l]);
295 return ret;
296 }
297
298 insn_t
299 loongarch_foreach_args (const char *format, const char *arg_strs[],
300 int32_t (*helper) (char esc1, char esc2,
301 const char *bit_field,
302 const char *arg, void *context),
303 void *context)
304 {
305 char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1];
306 const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1];
307 size_t i;
308 insn_t ret = 0;
309 int ok;
310
311 ok = loongarch_parse_format (format, esc1s, esc2s, bit_fields) == 0;
312
313 /* Make sure the num of actual args is equal to the num of escape. */
314 for (i = 0; esc1s[i] && arg_strs[i]; i++)
315 ;
316 ok = ok && !esc1s[i] && !arg_strs[i];
317
318 if (ok && helper)
319 {
320 for (i = 0; arg_strs[i]; i++)
321 ret |= loongarch_encode_imm (bit_fields[i],
322 helper (esc1s[i], esc2s[i],
323 bit_fields[i], arg_strs[i],
324 context));
325 ret |= helper ('\0', '\0', NULL, NULL, context);
326 }
327
328 return ret;
329 }
330
331 int
332 loongarch_check_format (const char *format)
333 {
334 char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1];
335 const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1];
336
337 if (!format)
338 return -1;
339
340 return loongarch_parse_format (format, esc1s, esc2s, bit_fields);
341 }
342
343 int
344 loongarch_check_macro (const char *format, const char *macro)
345 {
346 int num_of_args;
347 char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1];
348 const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1];
349
350 if (!format || !macro
351 || loongarch_parse_format (format, esc1s, esc2s, bit_fields) != 0)
352 return -1;
353
354 for (num_of_args = 0; esc1s[num_of_args]; num_of_args++)
355 ;
356
357 for (; macro[0]; macro++)
358 if (macro[0] == '%')
359 {
360 macro++;
361 if ('1' <= macro[0] && macro[0] <= '9')
362 {
363 if (num_of_args < macro[0] - '0')
364 /* Out of args num. */
365 return -1;
366 }
367 else if (macro[0] == 'f')
368 ;
369 else if (macro[0] == '%')
370 ;
371 else
372 return -1;
373 }
374 return 0;
375 }
376
377 static const char *
378 I (char esc_ch1 ATTRIBUTE_UNUSED, char esc_ch2 ATTRIBUTE_UNUSED,
379 const char *c_str)
380 {
381 return c_str;
382 }
383
384 char *
385 loongarch_expand_macro_with_format_map (
386 const char *format, const char *macro, const char *const arg_strs[],
387 const char *(*map) (char esc1, char esc2, const char *arg),
388 char *(*helper) (const char *const arg_strs[], void *context), void *context,
389 size_t len_str)
390 {
391 char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1];
392 const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1];
393 const char *src;
394 char *dest;
395
396 /* The expanded macro character length does not exceed 1000, and number of
397 label is 6 at most in the expanded macro. The len_str is the length of
398 str. */
399 char *buffer =(char *) malloc(1024 + 6 * len_str);
400
401 if (format)
402 loongarch_parse_format (format, esc1s, esc2s, bit_fields);
403
404 src = macro;
405 dest = buffer;
406
407 while (*src)
408 if (*src == '%')
409 {
410 src++;
411 if ('1' <= *src && *src <= '9')
412 {
413 size_t i = *src - '1';
414 const char *t = map (esc1s[i], esc2s[i], arg_strs[i]);
415 while (*t)
416 *dest++ = *t++;
417 }
418 else if (*src == '%')
419 *dest++ = '%';
420 else if (*src == 'f' && helper)
421 {
422 char *b, *t;
423 t = b = (*helper) (arg_strs, context);
424 if (b)
425 {
426 while (*t)
427 *dest++ = *t++;
428 free (b);
429 }
430 }
431 src++;
432 }
433 else
434 *dest++ = *src++;
435
436 *dest = '\0';
437 return buffer;
438 }
439
440 char *
441 loongarch_expand_macro (const char *macro, const char *const arg_strs[],
442 char *(*helper) (const char *const arg_strs[],
443 void *context),
444 void *context, size_t len_str)
445 {
446 return loongarch_expand_macro_with_format_map (NULL, macro, arg_strs, I,
447 helper, context, len_str);
448 }
449
450 size_t
451 loongarch_bits_imm_needed (int64_t imm, int si)
452 {
453 size_t ret;
454 if (si)
455 {
456 if (imm < 0)
457 {
458 uint64_t uimm = (uint64_t) imm;
459 uint64_t uimax = UINT64_C (1) << 63;
460 for (ret = 0; (uimm & uimax) != 0; uimm <<= 1, ret++)
461 ;
462 ret = 64 - ret + 1;
463 }
464 else
465 ret = loongarch_bits_imm_needed (imm, 0) + 1;
466 }
467 else
468 {
469 uint64_t t = imm;
470 for (ret = 0; t; t >>= 1, ret++)
471 ;
472 }
473 return ret;
474 }
475
476 void
477 loongarch_eliminate_adjacent_repeat_char (char *dest, char c)
478 {
479 if (c == '\0')
480 return;
481 char *src = dest;
482 while (*dest)
483 {
484 while (src[0] == c && src[0] == src[1])
485 src++;
486 *dest++ = *src++;
487 }
488 }