Wolfgang Thallergcc16 merge934c3885 months agoHistory
494 lines · 10.4 KB · C
RawDownload
/* LoongArch opcode support.   Copyright (C) 2021-2026 Free Software Foundation, Inc.   Contributed by Loongson Ltd.    This file is part of the GNU opcodes library.    This library is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 3, or (at your option)   any later version.    It is distributed in the hope that it will be useful, but WITHOUT   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public   License for more details.    You should have received a copy of the GNU General Public License   along with this program; see the file COPYING3.  If not,   see <http://www.gnu.org/licenses/>.  */#include "sysdep.h"#include <stdbool.h>#include "opcode/loongarch.h" intis_unsigned (const char *c_str){  if (c_str[0] == '0' && (c_str[1] == 'x' || c_str[1] == 'X'))    {      c_str += 2;      while (('a' <= *c_str && *c_str <= 'f')	     || ('A' <= *c_str && *c_str <= 'F')	     || ('0' <= *c_str && *c_str <= '9'))	c_str++;    }  else if (*c_str == '\0')    return 0;  else    while ('0' <= *c_str && *c_str <= '9')      c_str++;  return *c_str == '\0';} intis_signed (const char *c_str){  return *c_str == '-' ? is_unsigned (c_str + 1) : is_unsigned (c_str);} intloongarch_get_bit_field_width (const char *bit_field, char **end){  int width = 0;  char has_specify = 0, *bit_field_1 = (char *) bit_field;  if (bit_field_1 && *bit_field_1 != '\0')    while (1)      {	strtol (bit_field_1, &bit_field_1, 10); 	if (*bit_field_1 != ':')	  break;	bit_field_1++; 	width += strtol (bit_field_1, &bit_field_1, 10);	has_specify = 1; 	if (*bit_field_1 != '|')	  break;	bit_field_1++;      }  if (end)    *end = bit_field_1;  return has_specify ? width : -1;} int32_tloongarch_decode_imm (const char *bit_field, insn_t insn, int si){  int32_t ret = 0;  uint32_t t;  int len = 0, width, b_start;  char *bit_field_1 = (char *) bit_field;  while (1)    {      b_start = strtol (bit_field_1, &bit_field_1, 10);      if (*bit_field_1 != ':')	break;      width = strtol (bit_field_1 + 1, &bit_field_1, 10);      len += width;       t = insn;      t <<= sizeof (t) * 8 - width - b_start;      t >>= sizeof (t) * 8 - width;      ret <<= width;      ret |= t;       if (*bit_field_1 != '|')	break;      bit_field_1++;    }   if (*bit_field_1 == '<' && *(++bit_field_1) == '<')    {      width = atoi (bit_field_1 + 1);      ret <<= width;      len += width;    }  else if (*bit_field_1 == '+')    ret += atoi (bit_field_1 + 1);   /* Extend signed bit.  */  if (si)    {      uint32_t sign = 1u << (len - 1);      ret = (ret ^ sign) - sign;    }   return ret;} static insn_tloongarch_encode_imm (const char *bit_field, int32_t imm){  char *bit_field_1 = (char *) bit_field;  char *t = bit_field_1;  int width, b_start;  insn_t ret = 0;  uint32_t i;  uint32_t uimm = (uint32_t)imm;   width = loongarch_get_bit_field_width (t, &t);  if (width == -1)    return ret;   if (*t == '<' && *(++t) == '<')    width += atoi (t + 1);  else if (*t == '+')    uimm -= atoi (t + 1);   uimm = width ? (uimm << (sizeof (uimm) * 8 - width)) : 0;   while (1)    {      b_start = strtol (bit_field_1, &bit_field_1, 10);      if (*bit_field_1 != ':')	break;      width = strtol (bit_field_1 + 1, &bit_field_1, 10);      i = uimm;      i = width ? (i >> (sizeof (i) * 8 - width)) : 0;      i = (b_start == 32) ? 0 : (i << b_start);      ret |= i;      uimm = (width == 32) ? 0 : (uimm << width);       if (*bit_field_1 != '|')	break;      bit_field_1++;    }  return ret;} /* Parse such FORMAT   ""   "u"   "v0:5,r5:5,s10:10<<2"   "r0:5,r5:5,r10:5,u15:2+1"   "r,r,u0:5+32,u0:5+1"*/static intloongarch_parse_format (const char *format, char *esc1s, char *esc2s,			const char **bit_fields){  size_t arg_num = 0;   if (*format == '\0')    goto end;   while (1)    {      /* esc1    esc2	 for "[a-zA-Z][a-zA-Z]?"  */      if (('a' <= *format && *format <= 'z')	  || ('A' <= *format && *format <= 'Z'))	{	  *esc1s++ = *format++;	  if (('a' <= *format && *format <= 'z')	      || ('A' <= *format && *format <= 'Z'))	    *esc2s++ = *format++;	  else	    *esc2s++ = '\0';	}      else	return -1;       arg_num++;      if (MAX_ARG_NUM_PLUS_2 - 2 < arg_num)	/* Need larger MAX_ARG_NUM_PLUS_2.  */	return -1;       *bit_fields++ = format;       if ('0' <= *format && *format <= '9')	{	  /* For "[0-9]+:[0-9]+(\|[0-9]+:[0-9]+)*".  */	  while (1)	    {	      while ('0' <= *format && *format <= '9')		format++; 	      if (*format != ':')		return -1;	      format++; 	      if (!('0' <= *format && *format <= '9'))		return -1;	      while ('0' <= *format && *format <= '9')		format++; 	      if (*format != '|')		break;	      format++;	    } 	  /* For "((\+|<<)[1-9][0-9]*)?".  */	  do	    {	      if (*format == '+')		format++;	      else if (format[0] == '<' && format[1] == '<')		format += 2;	      else		break; 	      if (!('1' <= *format && *format <= '9'))		return -1;	      while ('0' <= *format && *format <= '9')		format++;	    }	  while (0);	}       if (*format == ',')	format++;      else if (*format == '\0')	break;      else	return -1;    }  end:  *esc1s = '\0';  return 0;} size_tloongarch_split_args_by_comma (char *args, const char *arg_strs[]){  size_t num = 0;   if (*args)    {      bool inquote = false;      arg_strs[num++] = args;      for (; *args; args++)	if (*args == '"')	  inquote = !inquote;	else if (*args == ',' && !inquote)	  {	    if (MAX_ARG_NUM_PLUS_2 - 1 == num)	      goto out;	    *args = '\0';	    arg_strs[num++] = args + 1;	  }       if (*(args - 1) == '"' && *arg_strs[num - 1] == '"')	{	  *(args - 1) = '\0';	  arg_strs[num - 1] += 1;	}    } out:  arg_strs[num] = NULL;  return num;} char *loongarch_cat_splited_strs (const char *arg_strs[]){  char *ret;  size_t n, l;   for (l = 0, n = 0; arg_strs[n]; n++)    l += strlen (arg_strs[n]);  ret = malloc (l + n + 1);  if (!ret)    return ret;   ret[0] = '\0';  if (0 < n)    strcat (ret, arg_strs[0]);  for (l = 1; l < n; l++)    strcat (ret, ","), strcat (ret, arg_strs[l]);  return ret;} insn_tloongarch_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){  char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1];  const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1];  size_t i;  insn_t ret = 0;  int ok;   ok = loongarch_parse_format (format, esc1s, esc2s, bit_fields) == 0;   /* Make sure the num of actual args is equal to the num of escape.  */  for (i = 0; esc1s[i] && arg_strs[i]; i++)    ;  ok = ok && !esc1s[i] && !arg_strs[i];   if (ok && helper)    {      for (i = 0; arg_strs[i]; i++)	ret |= loongarch_encode_imm (bit_fields[i],				     helper (esc1s[i], esc2s[i],					     bit_fields[i], arg_strs[i],					     context));      ret |= helper ('\0', '\0', NULL, NULL, context);    }   return ret;} intloongarch_check_format (const char *format){  char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1];  const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1];   if (!format)    return -1;   return loongarch_parse_format (format, esc1s, esc2s, bit_fields);} intloongarch_check_macro (const char *format, const char *macro){  int num_of_args;  char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1];  const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1];   if (!format || !macro      || loongarch_parse_format (format, esc1s, esc2s, bit_fields) != 0)    return -1;   for (num_of_args = 0; esc1s[num_of_args]; num_of_args++)    ;   for (; macro[0]; macro++)    if (macro[0] == '%')      {	macro++;	if ('1' <= macro[0] && macro[0] <= '9')	  {	    if (num_of_args < macro[0] - '0')	      /* Out of args num.  */	      return -1;	  }	else if (macro[0] == 'f')	  ;	else if (macro[0] == '%')	  ;	else	  return -1;      }  return 0;} static const char *I (char esc_ch1 ATTRIBUTE_UNUSED, char esc_ch2 ATTRIBUTE_UNUSED,   const char *c_str){  return c_str;} 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){  char esc1s[MAX_ARG_NUM_PLUS_2 - 1], esc2s[MAX_ARG_NUM_PLUS_2 - 1];  const char *bit_fields[MAX_ARG_NUM_PLUS_2 - 1];  const char *src;  char *dest;   /* The expanded macro character length does not exceed 1000, and number of     label is 6 at most in the expanded macro. The len_str is the length of     str.  */  char *buffer =(char *) malloc(1024 +  6 * len_str);   if (format)    loongarch_parse_format (format, esc1s, esc2s, bit_fields);   src = macro;  dest = buffer;   while (*src)    if (*src == '%')      {	src++;	if ('1' <= *src && *src <= '9')	  {	    size_t i = *src - '1';	    const char *t = map (esc1s[i], esc2s[i], arg_strs[i]);	    while (*t)	      *dest++ = *t++;	  }	else if (*src == '%')	  *dest++ = '%';	else if (*src == 'f' && helper)	  {	    char *b, *t;	    t = b = (*helper) (arg_strs, context);	    if (b)	      {		while (*t)		  *dest++ = *t++;		free (b);	      }	  }	src++;      }    else      *dest++ = *src++;   *dest = '\0';  return buffer;} 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){  return loongarch_expand_macro_with_format_map (NULL, macro, arg_strs, I,						 helper, context, len_str);} size_tloongarch_bits_imm_needed (int64_t imm, int si){  size_t ret;  if (si)    {      if (imm < 0)	{	  uint64_t uimm = (uint64_t) imm;	  uint64_t uimax = UINT64_C (1) << 63;	  for (ret = 0; (uimm & uimax) != 0; uimm <<= 1, ret++)	    ;	  ret = 64 - ret + 1;	}      else	ret = loongarch_bits_imm_needed (imm, 0) + 1;    }  else    {      uint64_t t = imm;      for (ret = 0; t; t >>= 1, ret++)	;    }  return ret;} voidloongarch_eliminate_adjacent_repeat_char (char *dest, char c){  if (c == '\0')    return;  char *src = dest;  while (*dest)    {      while (src[0] == c && src[0] == src[1])	src++;      *dest++ = *src++;    }}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t