xref: /netbsd-src/external/gpl3/binutils.old/dist/opcodes/loongarch-coder.c (revision c42dbd0ed2e61fe6eda8590caa852ccf34719964)
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 
23 int
is_unsigned(const char * c_str)24 is_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 
42 int
is_signed(const char * c_str)43 is_signed (const char *c_str)
44 {
45   return *c_str == '-' ? is_unsigned (c_str + 1) : is_unsigned (c_str);
46 }
47 
48 int
loongarch_get_bit_field_width(const char * bit_field,char ** end)49 loongarch_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 
74 int32_t
loongarch_decode_imm(const char * bit_field,insn_t insn,int si)75 loongarch_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 
119 static insn_t
loongarch_encode_imm(const char * bit_field,int32_t imm)120 loongarch_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 */
166 static int
loongarch_parse_format(const char * format,char * esc1s,char * esc2s,const char ** bit_fields)167 loongarch_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 
252 size_t
loongarch_split_args_by_comma(char * args,const char * arg_strs[])253 loongarch_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 
271 char *
loongarch_cat_splited_strs(const char * arg_strs[])272 loongarch_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 
291 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)292 loongarch_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 
324 int
loongarch_check_format(const char * format)325 loongarch_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 
336 int
loongarch_check_macro(const char * format,const char * macro)337 loongarch_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 
370 static const char *
I(char esc_ch1 ATTRIBUTE_UNUSED,char esc_ch2 ATTRIBUTE_UNUSED,const char * c_str)371 I (char esc_ch1 ATTRIBUTE_UNUSED, char esc_ch2 ATTRIBUTE_UNUSED,
372    const char *c_str)
373 {
374   return c_str;
375 }
376 
377 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)378 loongarch_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 
433 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)434 loongarch_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 
443 size_t
loongarch_bits_imm_needed(int64_t imm,int si)444 loongarch_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 
469 void
loongarch_eliminate_adjacent_repeat_char(char * dest,char c)470 loongarch_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