Coverage Report

Created: 2026-04-04 08:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/binutils-gdb/opcodes/loongarch-coder.c
Line
Count
Source
1
/* LoongArch opcode support.
2
   Copyright (C) 2021-2026 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
105k
{
52
105k
  int width = 0;
53
105k
  char has_specify = 0, *bit_field_1 = (char *) bit_field;
54
105k
  if (bit_field_1 && *bit_field_1 != '\0')
55
108k
    while (1)
56
108k
      {
57
108k
  strtol (bit_field_1, &bit_field_1, 10);
58
59
108k
  if (*bit_field_1 != ':')
60
0
    break;
61
108k
  bit_field_1++;
62
63
108k
  width += strtol (bit_field_1, &bit_field_1, 10);
64
108k
  has_specify = 1;
65
66
108k
  if (*bit_field_1 != '|')
67
105k
    break;
68
3.24k
  bit_field_1++;
69
3.24k
      }
70
105k
  if (end)
71
105k
    *end = bit_field_1;
72
105k
  return has_specify ? width : -1;
73
105k
}
74
75
int32_t
76
loongarch_decode_imm (const char *bit_field, insn_t insn, int si)
77
210k
{
78
210k
  int32_t ret = 0;
79
210k
  uint32_t t;
80
210k
  int len = 0, width, b_start;
81
210k
  char *bit_field_1 = (char *) bit_field;
82
216k
  while (1)
83
216k
    {
84
216k
      b_start = strtol (bit_field_1, &bit_field_1, 10);
85
216k
      if (*bit_field_1 != ':')
86
0
  break;
87
216k
      width = strtol (bit_field_1 + 1, &bit_field_1, 10);
88
216k
      len += width;
89
90
216k
      t = insn;
91
216k
      t <<= sizeof (t) * 8 - width - b_start;
92
216k
      t >>= sizeof (t) * 8 - width;
93
216k
      ret <<= width;
94
216k
      ret |= t;
95
96
216k
      if (*bit_field_1 != '|')
97
210k
  break;
98
6.48k
      bit_field_1++;
99
6.48k
    }
100
101
210k
  if (*bit_field_1 == '<' && *(++bit_field_1) == '<')
102
20.9k
    {
103
20.9k
      width = atoi (bit_field_1 + 1);
104
20.9k
      ret <<= width;
105
20.9k
      len += width;
106
20.9k
    }
107
189k
  else if (*bit_field_1 == '+')
108
2.24k
    ret += atoi (bit_field_1 + 1);
109
110
  /* Extend signed bit.  */
111
210k
  if (si)
112
105k
    {
113
105k
      uint32_t sign = 1u << (len - 1);
114
105k
      ret = (ret ^ sign) - sign;
115
105k
    }
116
117
210k
  return ret;
118
210k
}
119
120
static insn_t
121
loongarch_encode_imm (const char *bit_field, int32_t imm)
122
105k
{
123
105k
  char *bit_field_1 = (char *) bit_field;
124
105k
  char *t = bit_field_1;
125
105k
  int width, b_start;
126
105k
  insn_t ret = 0;
127
105k
  uint32_t i;
128
105k
  uint32_t uimm = (uint32_t)imm;
129
130
105k
  width = loongarch_get_bit_field_width (t, &t);
131
105k
  if (width == -1)
132
0
    return ret;
133
134
105k
  if (*t == '<' && *(++t) == '<')
135
10.4k
    width += atoi (t + 1);
136
94.6k
  else if (*t == '+')
137
1.12k
    uimm -= atoi (t + 1);
138
139
105k
  uimm = width ? (uimm << (sizeof (uimm) * 8 - width)) : 0;
140
141
108k
  while (1)
142
108k
    {
143
108k
      b_start = strtol (bit_field_1, &bit_field_1, 10);
144
108k
      if (*bit_field_1 != ':')
145
0
  break;
146
108k
      width = strtol (bit_field_1 + 1, &bit_field_1, 10);
147
108k
      i = uimm;
148
108k
      i = width ? (i >> (sizeof (i) * 8 - width)) : 0;
149
108k
      i = (b_start == 32) ? 0 : (i << b_start);
150
108k
      ret |= i;
151
108k
      uimm = (width == 32) ? 0 : (uimm << width);
152
153
108k
      if (*bit_field_1 != '|')
154
105k
  break;
155
3.24k
      bit_field_1++;
156
3.24k
    }
157
105k
  return ret;
158
105k
}
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
36.5k
{
171
36.5k
  size_t arg_num = 0;
172
173
36.5k
  if (*format == '\0')
174
12
    goto end;
175
176
105k
  while (1)
177
105k
    {
178
      /* esc1    esc2
179
   for "[a-zA-Z][a-zA-Z]?"  */
180
105k
      if (('a' <= *format && *format <= 'z')
181
0
    || ('A' <= *format && *format <= 'Z'))
182
105k
  {
183
105k
    *esc1s++ = *format++;
184
105k
    if (('a' <= *format && *format <= 'z')
185
93.3k
        || ('A' <= *format && *format <= 'Z'))
186
11.7k
      *esc2s++ = *format++;
187
93.3k
    else
188
93.3k
      *esc2s++ = '\0';
189
105k
  }
190
0
      else
191
0
  return -1;
192
193
105k
      arg_num++;
194
105k
      if (MAX_ARG_NUM_PLUS_2 - 2 < arg_num)
195
  /* Need larger MAX_ARG_NUM_PLUS_2.  */
196
0
  return -1;
197
198
105k
      *bit_fields++ = format;
199
200
105k
      if ('0' <= *format && *format <= '9')
201
105k
  {
202
    /* For "[0-9]+:[0-9]+(\|[0-9]+:[0-9]+)*".  */
203
108k
    while (1)
204
108k
      {
205
255k
        while ('0' <= *format && *format <= '9')
206
146k
    format++;
207
208
108k
        if (*format != ':')
209
0
    return -1;
210
108k
        format++;
211
212
108k
        if (!('0' <= *format && *format <= '9'))
213
0
    return -1;
214
234k
        while ('0' <= *format && *format <= '9')
215
126k
    format++;
216
217
108k
        if (*format != '|')
218
105k
    break;
219
3.24k
        format++;
220
3.24k
      }
221
222
    /* For "((\+|<<)[1-9][0-9]*)?".  */
223
105k
    do
224
105k
      {
225
105k
        if (*format == '+')
226
1.12k
    format++;
227
104k
        else if (format[0] == '<' && format[1] == '<')
228
10.4k
    format += 2;
229
93.5k
        else
230
93.5k
    break;
231
232
11.6k
        if (!('1' <= *format && *format <= '9'))
233
0
    return -1;
234
23.2k
        while ('0' <= *format && *format <= '9')
235
11.6k
    format++;
236
11.6k
      }
237
105k
    while (0);
238
105k
  }
239
240
105k
      if (*format == ',')
241
68.6k
  format++;
242
36.5k
      else if (*format == '\0')
243
36.5k
  break;
244
0
      else
245
0
  return -1;
246
105k
    }
247
248
36.5k
 end:
249
36.5k
  *esc1s = '\0';
250
36.5k
  return 0;
251
36.5k
}
252
253
size_t
254
loongarch_split_args_by_comma (char *args, const char *arg_strs[])
255
36.5k
{
256
36.5k
  size_t num = 0;
257
258
36.5k
  if (*args)
259
36.5k
    {
260
36.5k
      bool inquote = false;
261
36.5k
      arg_strs[num++] = args;
262
640k
      for (; *args; args++)
263
604k
  if (*args == '"')
264
0
    inquote = !inquote;
265
604k
  else if (*args == ',' && !inquote)
266
68.6k
    {
267
68.6k
      if (MAX_ARG_NUM_PLUS_2 - 1 == num)
268
0
        goto out;
269
68.6k
      *args = '\0';
270
68.6k
      arg_strs[num++] = args + 1;
271
68.6k
    }
272
273
36.5k
      if (*(args - 1) == '"' && *arg_strs[num - 1] == '"')
274
0
  {
275
0
    *(args - 1) = '\0';
276
0
    arg_strs[num - 1] += 1;
277
0
  }
278
36.5k
    }
279
36.5k
 out:
280
36.5k
  arg_strs[num] = NULL;
281
36.5k
  return num;
282
36.5k
}
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
36.5k
{
311
36.5k
  char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1];
312
36.5k
  const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1];
313
36.5k
  size_t i;
314
36.5k
  insn_t ret = 0;
315
36.5k
  int ok;
316
317
36.5k
  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
141k
  for (i = 0; esc1s[i] && arg_strs[i]; i++)
321
105k
    ;
322
36.5k
  ok = ok && !esc1s[i] && !arg_strs[i];
323
324
36.5k
  if (ok && helper)
325
36.5k
    {
326
141k
      for (i = 0; arg_strs[i]; i++)
327
105k
  ret |= loongarch_encode_imm (bit_fields[i],
328
105k
             helper (esc1s[i], esc2s[i],
329
105k
               bit_fields[i], arg_strs[i],
330
105k
               context));
331
36.5k
      ret |= helper ('\0', '\0', NULL, NULL, context);
332
36.5k
    }
333
334
36.5k
  return ret;
335
36.5k
}
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
}