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