Coverage Report

Created: 2024-05-21 06:29

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