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