Coverage Report

Created: 2025-06-24 06:45

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