123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481 |
- /* LoongArch opcode support.
- Copyright (C) 2021-2022 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 "opcode/loongarch.h"
- int
- is_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';
- }
- int
- is_signed (const char *c_str)
- {
- return *c_str == '-' ? is_unsigned (c_str + 1) : is_unsigned (c_str);
- }
- int
- loongarch_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_t
- loongarch_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_t
- loongarch_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 int
- loongarch_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_t
- loongarch_split_args_by_comma (char *args, const char *arg_strs[])
- {
- size_t num = 0;
- if (*args)
- arg_strs[num++] = args;
- for (; *args; args++)
- if (*args == ',')
- {
- if (MAX_ARG_NUM_PLUS_2 - 1 == num)
- break;
- else
- *args = '\0', arg_strs[num++] = args + 1;
- }
- 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_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)
- {
- 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;
- }
- int
- loongarch_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);
- }
- int
- loongarch_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_t
- loongarch_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;
- }
- void
- loongarch_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++;
- }
- }
|