(root)/
binutils-2.41/
opcodes/
loongarch-coder.c
       1  /* LoongArch opcode support.
       2     Copyright (C) 2021-2023 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
      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
      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
      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
      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
     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
     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
     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 *
     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
     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
     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
     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 *
     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 *
     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 *
     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
     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
     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  }