Home | History | Annotate | Line # | Download | only in opcodes
      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 {
     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
     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
     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
     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
    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
    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
    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 *
    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
    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
    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
    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 *
    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 *
    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 *
    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
    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
    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