From: Jan Beulich Date: Tue, 4 Oct 2022 07:46:11 +0000 (+0200) Subject: RISC-V/gas: allow generating up to 176-bit instructions with .insn X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=bb996692bd9654d6f2345ab65742796d5fde6829;p=binutils-gdb.git RISC-V/gas: allow generating up to 176-bit instructions with .insn For the time being simply utilize O_big to avoid widening other fields, bypassing append_insn() etc. --- diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c index a47d36ceb72..22385d1baa0 100644 --- a/gas/config/tc-riscv.c +++ b/gas/config/tc-riscv.c @@ -3389,8 +3389,15 @@ riscv_ip_hardcode (char *str, do { expression (imm_expr); - if (imm_expr->X_op != O_constant) + switch (imm_expr->X_op) { + case O_constant: + values[num++] = (insn_t) imm_expr->X_add_number; + break; + case O_big: + values[num++] = generic_bignum[0]; + break; + default: /* The first value isn't constant, so it should be .insn . We have been parsed it in the riscv_ip. */ @@ -3398,9 +3405,8 @@ riscv_ip_hardcode (char *str, return error; return _("values must be constant"); } - values[num++] = (insn_t) imm_expr->X_add_number; } - while (*input_line_pointer++ == ',' && num < 2); + while (*input_line_pointer++ == ',' && num < 2 && imm_expr->X_op != O_big); input_line_pointer--; if (*input_line_pointer != '\0') @@ -3410,8 +3416,22 @@ riscv_ip_hardcode (char *str, insn->match = values[num - 1]; create_insn (ip, insn); unsigned int bytes = riscv_insn_length (insn->match); - if ((bytes < sizeof(values[0]) && values[num - 1] >> (8 * bytes) != 0) - || (num == 2 && values[0] != bytes)) + + if (num == 2 && values[0] != bytes) + return _("value conflicts with instruction length"); + + if (imm_expr->X_op == O_big) + { + if (bytes != imm_expr->X_add_number * CHARS_PER_LITTLENUM) + return _("value conflicts with instruction length"); + char *f = frag_more (bytes); + for (num = 0; num < imm_expr->X_add_number; ++num) + number_to_chars_littleendian (f + num * CHARS_PER_LITTLENUM, + generic_bignum[num], CHARS_PER_LITTLENUM); + return NULL; + } + + if (bytes < sizeof(values[0]) && values[num - 1] >> (8 * bytes) != 0) return _("value conflicts with instruction length"); return NULL; @@ -4476,7 +4496,7 @@ s_riscv_insn (int x ATTRIBUTE_UNUSED) else as_bad ("%s `%s'", error.msg, error.statement); } - else + else if (imm_expr.X_op != O_big) { gas_assert (insn.insn_mo->pinfo != INSN_MACRO); append_insn (&insn, &imm_expr, imm_reloc); diff --git a/gas/testsuite/gas/riscv/insn-dwarf.d b/gas/testsuite/gas/riscv/insn-dwarf.d index a975b1464c0..89dc8d58ff0 100644 --- a/gas/testsuite/gas/riscv/insn-dwarf.d +++ b/gas/testsuite/gas/riscv/insn-dwarf.d @@ -65,8 +65,14 @@ insn.s +60 +0xac.* insn.s +61 +0xb0.* insn.s +62 +0xb6.* insn.s +63 +0xbe.* -insn.s +64 +0xc0.* -insn.s +65 +0xc4.* -insn.s +66 +0xca.* -insn.s +- +0xd2 +insn.s +64 +0xc8.* +insn.s +65 +0xd4.* +insn.s +66 +0xea.* +insn.s +67 +0xec.* +insn.s +68 +0xf0.* +insn.s +69 +0xf6.* +insn.s +70 +0xfe.* +insn.s +71 +0x108.* +insn.s +72 +0x114.* +insn.s +- +0x12a #pass diff --git a/gas/testsuite/gas/riscv/insn-fail.l b/gas/testsuite/gas/riscv/insn-fail.l index e47d106b39b..c5d35aa508f 100644 --- a/gas/testsuite/gas/riscv/insn-fail.l +++ b/gas/testsuite/gas/riscv/insn-fail.l @@ -5,3 +5,13 @@ .*Error: unrecognized values `0x4,0x5,0x6' .*Error: value conflicts with instruction length `0x4,0x0001' .*Error: value conflicts with instruction length `0x2,0x00000013' +.*Error: value conflicts with instruction length `0x10+1f' +.*Error: value conflicts with instruction length `6,0x10+1f' +.*Error: value conflicts with instruction length `0x10+3f' +.*Error: value conflicts with instruction length `8,0x10+3f' +.*Error: value conflicts with instruction length `0x10+7f' +.*Error: value conflicts with instruction length `10,0x10+7f' +.*Error: value conflicts with instruction length `0x10+107f' +.*Error: value conflicts with instruction length `12,0x10+107f' +.*Error: value conflicts with instruction length `0x10+607f' +.*Error: value conflicts with instruction length `22,0x10+607f' diff --git a/gas/testsuite/gas/riscv/insn-fail.s b/gas/testsuite/gas/riscv/insn-fail.s index 064211d985d..861d91ac479 100644 --- a/gas/testsuite/gas/riscv/insn-fail.s +++ b/gas/testsuite/gas/riscv/insn-fail.s @@ -4,3 +4,13 @@ .insn 0x4, 0x5, 0x6 .insn 0x4, 0x0001 .insn 0x2, 0x00000013 + .insn 0x100000000001f + .insn 6, 0x100000000001f + .insn 0x1000000000000003f + .insn 8, 0x1000000000000003f + .insn 0x10000000000000000007f + .insn 10, 0x10000000000000000007f + .insn 0x100000000000000000000107f + .insn 12, 0x100000000000000000000107f + .insn 0x10000000000000000000000000000000000000000607f + .insn 22, 0x10000000000000000000000000000000000000000607f diff --git a/gas/testsuite/gas/riscv/insn-na.d b/gas/testsuite/gas/riscv/insn-na.d index b4a664b1eed..66dce71ebc2 100644 --- a/gas/testsuite/gas/riscv/insn-na.d +++ b/gas/testsuite/gas/riscv/insn-na.d @@ -63,7 +63,13 @@ Disassembly of section .text: [^:]+:[ ]+00000013[ ]+addi[ ]+zero,zero,0 [^:]+:[ ]+001f 0000 0000[ ].* [^:]+:[ ]+0000003f 00000000[ ].* +[^:]+:[ ]+007f 0000 0000 0000 0000[ ]+[._a-z].* +[^:]+:[ ]+0000107f 00000000 00000000[ ]+[._a-z].* +[^:]+:[ ]+607f 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000[ ]+[._a-z].* [^:]+:[ ]+0001[ ]+c\.addi[ ]+zero,0 [^:]+:[ ]+00000013[ ]+addi[ ]+zero,zero,0 [^:]+:[ ]+001f 0000 0000[ ].* [^:]+:[ ]+0000003f 00000000[ ].* +[^:]+:[ ]+007f 0000 0000 0000 0000[ ]+[._a-z].* +[^:]+:[ ]+0000107f 00000000 00000000[ ]+[._a-z].* +[^:]+:[ ]+607f 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000[ ]+[._a-z].* diff --git a/gas/testsuite/gas/riscv/insn.d b/gas/testsuite/gas/riscv/insn.d index 14b15d8315d..2e5d35b3970 100644 --- a/gas/testsuite/gas/riscv/insn.d +++ b/gas/testsuite/gas/riscv/insn.d @@ -74,7 +74,21 @@ Disassembly of section .text: [^:]+:[ ]+00000013[ ]+nop [^:]+:[ ]+001f 0000 0000[ ].* [^:]+:[ ]+0000003f 00000000[ ].* +[^:]+:[ ]+007f 0000 0000 0000[ ]+[._a-z].* +[^:]+:[ ]+0000 ? +[^:]+:[ ]+0000107f 00000000[ ]+[._a-z].* +[^:]+:[ ]+00000000 ? +[^:]+:[ ]+607f 0000 0000 0000[ ]+[._a-z].* +[^:]+:[ ]+0000 0000 0000 0000 ? +[^:]+:[ ]+0000 0000 0000 ? [^:]+:[ ]+0001[ ]+nop [^:]+:[ ]+00000013[ ]+nop [^:]+:[ ]+001f 0000 0000[ ].* [^:]+:[ ]+0000003f 00000000[ ].* +[^:]+:[ ]+007f 0000 0000 0000[ ]+[._a-z].* +[^:]+:[ ]+0000 ? +[^:]+:[ ]+0000107f 00000000[ ]+[._a-z].* +[^:]+:[ ]+00000000 ? +[^:]+:[ ]+607f 0000 0000 0000[ ]+[._a-z].* +[^:]+:[ ]+0000 0000 0000 0000 ? +[^:]+:[ ]+0000 0000 0000 ? diff --git a/gas/testsuite/gas/riscv/insn.s b/gas/testsuite/gas/riscv/insn.s index 993615eb747..94f62fe5672 100644 --- a/gas/testsuite/gas/riscv/insn.s +++ b/gas/testsuite/gas/riscv/insn.s @@ -60,7 +60,13 @@ target: .insn 0x00000013 .insn 0x0000001f .insn 0x0000003f + .insn 0x007f + .insn 0x107f + .insn 0x607f .insn 0x2, 0x0001 .insn 0x4, 0x00000013 .insn 6, 0x0000001f .insn 8, 0x0000003f + .insn 10, 0x007f + .insn 12, 0x107f + .insn 22, 0x607f diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h index dd2569f6d55..9417dcf00c5 100644 --- a/include/opcode/riscv.h +++ b/include/opcode/riscv.h @@ -37,6 +37,9 @@ static inline unsigned int riscv_insn_length (insn_t insn) return 6; if ((insn & 0x7f) == 0x3f) /* 64-bit instructions. */ return 8; + /* 80- ... 176-bit instructions. */ + if ((insn & 0x7f) == 0x7f && (insn & 0x7000) != 0x7000) + return 10 + ((insn >> 11) & 0xe); /* Longer instructions not supported at the moment. */ return 2; }