diff options
author | liuzhensong <liuzhensong@loongson.cn> | 2021-10-22 16:42:04 +0800 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2021-10-24 21:36:31 +1030 |
commit | 6cc76c40a99bd13d69a311cae5ec891bd1d1dbf2 (patch) | |
tree | 091be65314dbf2b4b4030edb7a7f8140504f230b /opcodes/loongarch-coder.c | |
parent | e214f8db56f65531b0a5ec296c42339dcaa5af31 (diff) | |
download | binutils-gdb-6cc76c40a99bd13d69a311cae5ec891bd1d1dbf2.tar.gz |
LoongArch opcodes support
2021-10-22 Chenghua Xu <xuchenghua@loongson.cn>
Zhensong Liu <liuzhensong@loongson.cn>
Weinan Liu <liuweinan@loongson.cn>
include/
* opcode/loongarch.h: New.
* dis-asm.h: Declare print_loongarch_disassembler_options.
opcodes/
* Makefile.am: Add LoongArch.
* configure.ac: Likewise.
* disassemble.c: Likewise.
* disassemble.h: Declare print_insn_loongarch.
* loongarch-coder.c: New.
* loongarch-dis.c: New.
* loongarch-opc.c: New.
* Makefile.in: Regenerate.
* configure: Regenerate.
* po/POTFILES.in: Regenerate.
Diffstat (limited to 'opcodes/loongarch-coder.c')
-rw-r--r-- | opcodes/loongarch-coder.c | 473 |
1 files changed, 473 insertions, 0 deletions
diff --git a/opcodes/loongarch-coder.c b/opcodes/loongarch-coder.c new file mode 100644 index 00000000000..9c46ee463b2 --- /dev/null +++ b/opcodes/loongarch-coder.c @@ -0,0 +1,473 @@ +/* LoongArch opcode support. + Copyright (C) 2021 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); + + if (si) + { + ret <<= sizeof (ret) * 8 - len; + ret >>= sizeof (ret) * 8 - len; + } + 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 <<= sizeof (uimm) * 8 - width; + 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 >>= sizeof (i) * 8 - width; + i <<= b_start; + ret |= i; + 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) +{ + 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; + char buffer[8192]; + + 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 strdup (buffer); +} + +char * +loongarch_expand_macro (const char *macro, const char *const arg_strs[], + char *(*helper) (const char *const arg_strs[], + void *context), + void *context) +{ + return loongarch_expand_macro_with_format_map (NULL, macro, arg_strs, I, + helper, context); +} + +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++; + } +} |