1/* LoongArch opcode support.
2   Copyright (C) 2021-2022 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
23int
24is_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
42int
43is_signed (const char *c_str)
44{
45  return *c_str == '-' ? is_unsigned (c_str + 1) : is_unsigned (c_str);
46}
47
48int
49loongarch_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
74int32_t
75loongarch_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
119static insn_t
120loongarch_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*/
166static int
167loongarch_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
252size_t
253loongarch_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  arg_strs[num] = NULL;
268  return num;
269}
270
271char *
272loongarch_cat_splited_strs (const char *arg_strs[])
273{
274  char *ret;
275  size_t n, l;
276
277  for (l = 0, n = 0; arg_strs[n]; n++)
278    l += strlen (arg_strs[n]);
279  ret = malloc (l + n + 1);
280  if (!ret)
281    return ret;
282
283  ret[0] = '\0';
284  if (0 < n)
285    strcat (ret, arg_strs[0]);
286  for (l = 1; l < n; l++)
287    strcat (ret, ","), strcat (ret, arg_strs[l]);
288  return ret;
289}
290
291insn_t
292loongarch_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{
298  char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1];
299  const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1];
300  size_t i;
301  insn_t ret = 0;
302  int ok;
303
304  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  for (i = 0; esc1s[i] && arg_strs[i]; i++)
308    ;
309  ok = ok && !esc1s[i] && !arg_strs[i];
310
311  if (ok && helper)
312    {
313      for (i = 0; arg_strs[i]; i++)
314	ret |= loongarch_encode_imm (bit_fields[i],
315				     helper (esc1s[i], esc2s[i],
316					     bit_fields[i], arg_strs[i],
317					     context));
318      ret |= helper ('\0', '\0', NULL, NULL, context);
319    }
320
321  return ret;
322}
323
324int
325loongarch_check_format (const char *format)
326{
327  char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1];
328  const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1];
329
330  if (!format)
331    return -1;
332
333  return loongarch_parse_format (format, esc1s, esc2s, bit_fields);
334}
335
336int
337loongarch_check_macro (const char *format, const char *macro)
338{
339  int num_of_args;
340  char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1];
341  const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1];
342
343  if (!format || !macro
344      || loongarch_parse_format (format, esc1s, esc2s, bit_fields) != 0)
345    return -1;
346
347  for (num_of_args = 0; esc1s[num_of_args]; num_of_args++)
348    ;
349
350  for (; macro[0]; macro++)
351    if (macro[0] == '%')
352      {
353	macro++;
354	if ('1' <= macro[0] && macro[0] <= '9')
355	  {
356	    if (num_of_args < macro[0] - '0')
357	      /* Out of args num.  */
358	      return -1;
359	  }
360	else if (macro[0] == 'f')
361	  ;
362	else if (macro[0] == '%')
363	  ;
364	else
365	  return -1;
366      }
367  return 0;
368}
369
370static const char *
371I (char esc_ch1 ATTRIBUTE_UNUSED, char esc_ch2 ATTRIBUTE_UNUSED,
372   const char *c_str)
373{
374  return c_str;
375}
376
377char *
378loongarch_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{
384  char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1];
385  const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1];
386  const char *src;
387  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  char *buffer =(char *) malloc(1024 +  6 * len_str);
393
394  if (format)
395    loongarch_parse_format (format, esc1s, esc2s, bit_fields);
396
397  src = macro;
398  dest = buffer;
399
400  while (*src)
401    if (*src == '%')
402      {
403	src++;
404	if ('1' <= *src && *src <= '9')
405	  {
406	    size_t i = *src - '1';
407	    const char *t = map (esc1s[i], esc2s[i], arg_strs[i]);
408	    while (*t)
409	      *dest++ = *t++;
410	  }
411	else if (*src == '%')
412	  *dest++ = '%';
413	else if (*src == 'f' && helper)
414	  {
415	    char *b, *t;
416	    t = b = (*helper) (arg_strs, context);
417	    if (b)
418	      {
419		while (*t)
420		  *dest++ = *t++;
421		free (b);
422	      }
423	  }
424	src++;
425      }
426    else
427      *dest++ = *src++;
428
429  *dest = '\0';
430  return buffer;
431}
432
433char *
434loongarch_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{
439  return loongarch_expand_macro_with_format_map (NULL, macro, arg_strs, I,
440						 helper, context, len_str);
441}
442
443size_t
444loongarch_bits_imm_needed (int64_t imm, int si)
445{
446  size_t ret;
447  if (si)
448    {
449      if (imm < 0)
450	{
451	  uint64_t uimm = (uint64_t) imm;
452	  uint64_t uimax = UINT64_C (1) << 63;
453	  for (ret = 0; (uimm & uimax) != 0; uimm <<= 1, ret++)
454	    ;
455	  ret = 64 - ret + 1;
456	}
457      else
458	ret = loongarch_bits_imm_needed (imm, 0) + 1;
459    }
460  else
461    {
462      uint64_t t = imm;
463      for (ret = 0; t; t >>= 1, ret++)
464	;
465    }
466  return ret;
467}
468
469void
470loongarch_eliminate_adjacent_repeat_char (char *dest, char c)
471{
472  if (c == '\0')
473    return;
474  char *src = dest;
475  while (*dest)
476    {
477      while (src[0] == c && src[0] == src[1])
478	src++;
479      *dest++ = *src++;
480    }
481}
482