]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
RISC-V: T-HEAD: Fix wrong instruction encoding for th.vsetvli
authorJin Ma <jinma@linux.alibaba.com>
Thu, 4 Jan 2024 02:17:40 +0000 (10:17 +0800)
committerNelson Chu <nelson@rivosinc.com>
Fri, 5 Jan 2024 01:59:48 +0000 (09:59 +0800)
Since the particularity of "th.vsetvli" was not taken into account in the
initial support patches for XTheadVector, the program operation failed
due to instruction coding errors. According to T-Head SPEC ([1]), the
"vsetvl" in the XTheadVector extension consists of SEW, LMUL and EDIV,
which is quite different from the "V" extension. Therefore, we cannot
simply reuse the processing of vsetvl in V extension.

We have set up tens of thousands of test cases to ensure that no
further encoding issues are there, and and execute all compiled test
files on real HW and make sure they don't trigger SIGILL.

Ref:
[1] https://github.com/T-head-Semi/thead-extension-spec/releases/download/2.3.0/xthead-2023-11-10-2.3.0.pdf

Co-developed-by: Lifang Xia <lifang_xia@linux.alibaba.com>
Co-developed-by: Christoph Müllner <christoph.muellner@vrull.eu>
gas/ChangeLog:

* config/tc-riscv.c (validate_riscv_insn): Add handling for
th.vsetvli.
(my_getThVsetvliExpression): New function.
(riscv_ip): Likewise.
* testsuite/gas/riscv/x-thead-vector.d: Likewise.
* testsuite/gas/riscv/x-thead-vector.s: Likewise.

include/ChangeLog:

* opcode/riscv.h (OP_MASK_XTHEADVLMUL): New macro.
(OP_SH_XTHEADVLMUL): Likewise.
(OP_MASK_XTHEADVSEW): Likewise.
(OP_SH_XTHEADVSEW): Likewise.
(OP_MASK_XTHEADVEDIV): Likewise.
(OP_SH_XTHEADVEDIV): Likewise.
(OP_MASK_XTHEADVTYPE_RES): Likewise.
(OP_SH_XTHEADVTYPE_RES): Likewise.

opcodes/ChangeLog:

* riscv-dis.c (print_insn_args): Likewise.
* riscv-opc.c: Likewise.

gas/config/tc-riscv.c
gas/testsuite/gas/riscv/x-thead-vector.d
gas/testsuite/gas/riscv/x-thead-vector.s
include/opcode/riscv.h
opcodes/riscv-dis.c
opcodes/riscv-opc.c

index 1d075fda216167e2890d930adeaf600d42a5a6eb..a4161420128fd8a05f433757adb12c6d3acdaa56 100644 (file)
@@ -1467,6 +1467,15 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length)
                size_t s;
                switch (*++oparg)
                  {
+                 case 'V':
+                   switch (*++oparg)
+                     {
+                     case 'c': /* Vtypei for th.vsetvli.  */
+                       used_bits |= ENCODE_RVV_VC_IMM (-1U); break;
+                     default:
+                       goto unknown_validate_operand;
+                     }
+                     break;
                  case 'l': /* Integer immediate, literal.  */
                    oparg += strcspn(oparg, ",") - 1;
                    break;
@@ -2423,6 +2432,59 @@ my_getVsetvliExpression (expressionS *ep, char *str)
     }
 }
 
+/* Parse string STR as a th.vsetvli operand.  Store the expression in *EP.
+   On exit, EXPR_PARSE_END points to the first character after the
+   expression.  */
+
+static void
+my_getThVsetvliExpression (expressionS *ep, char *str)
+{
+  unsigned int vsew_value = 0, vlen_value = 0, vediv_value = 0;
+  bfd_boolean vsew_found = FALSE, vlen_found = FALSE, vediv_found = FALSE;
+
+  if (arg_lookup (&str, riscv_vsew, ARRAY_SIZE (riscv_vsew),
+                 &vsew_value))
+    {
+      if (*str == ',')
+       ++str;
+      if (vsew_found)
+       as_bad (_("multiple vsew constants"));
+      vsew_found = TRUE;
+    }
+
+  if (arg_lookup (&str, riscv_th_vlen, ARRAY_SIZE (riscv_th_vlen),
+                 &vlen_value))
+    {
+      if (*str == ',')
+       ++str;
+      if (vlen_found)
+       as_bad (_("multiple vlen constants"));
+      vlen_found = TRUE;
+    }
+  if (arg_lookup (&str, riscv_th_vediv, ARRAY_SIZE (riscv_th_vediv),
+                 &vediv_value))
+    {
+      if (*str == ',')
+       ++str;
+      if (vediv_found)
+       as_bad (_("multiple vediv constants"));
+      vediv_found = TRUE;
+    }
+
+  if (vlen_found || vediv_found || vsew_found)
+    {
+      ep->X_op = O_constant;
+      ep->X_add_number
+       = (vediv_value << 5) | (vsew_value << 2) | (vlen_value);
+      expr_parse_end = str;
+    }
+  else
+    {
+      my_getExpression (ep, str);
+      str = expr_parse_end;
+    }
+}
+
 /* Detect and handle implicitly zero load-store offsets.  For example,
    "lw t0, (t1)" is shorthand for "lw t0, 0(t1)".  Return true if such
    an implicit offset was detected.  */
@@ -3624,6 +3686,23 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
                    bool sign;
                    switch (*++oparg)
                      {
+                     case 'V':
+                       /* Vtypei for th.vsetvli.  */
+                       ++oparg;
+                       if (*oparg != 'c')
+                         goto unknown_riscv_ip_operand;
+
+                       my_getThVsetvliExpression (imm_expr, asarg);
+                       check_absolute_expr (ip, imm_expr, FALSE);
+                       if (!VALID_RVV_VC_IMM (imm_expr->X_add_number))
+                         as_bad (_("bad value for th.vsetvli immediate field, "
+                                 "value must be 0..2047"));
+                       ip->insn_opcode
+                         |= ENCODE_RVV_VC_IMM (imm_expr->X_add_number);
+                       imm_expr->X_op = O_absent;
+                       asarg = expr_parse_end;
+                       continue;
+
                      case 'l': /* Integer immediate, literal.  */
                        n = strcspn (++oparg, ",");
                        if (strncmp (oparg, asarg, n))
index 441bd0e660f481cd50ce526d1f751600fc61ab2f..836150a149891fb9188b230b26f5e26b78d1d3fe 100644 (file)
@@ -8,8 +8,9 @@ Disassembly of section .text:
 
 0+000 <.text>:
 [      ]+[0-9a-f]+:[   ]+80c5f557[     ]+th.vsetvl[    ]+a0,a1,a2
-[      ]+[0-9a-f]+:[   ]+0005f557[     ]+th.vsetvli[   ]+a0,a1,e8,m1,tu,mu
+[      ]+[0-9a-f]+:[   ]+0005f557[     ]+th.vsetvli[   ]+a0,a1,e8,m1,d1
 [      ]+[0-9a-f]+:[   ]+7ff5f557[     ]+th.vsetvli[   ]+a0,a1,2047
+[      ]+[0-9a-f]+:[   ]+0455f557[     ]+th.vsetvli[   ]+a0,a1,e16,m2,d4
 [      ]+[0-9a-f]+:[   ]+12050207[     ]+th.vlb.v[     ]+v4,\(a0\)
 [      ]+[0-9a-f]+:[   ]+12050207[     ]+th.vlb.v[     ]+v4,\(a0\)
 [      ]+[0-9a-f]+:[   ]+10050207[     ]+th.vlb.v[     ]+v4,\(a0\),v0.t
index 413f4a83a940f108d8cf2b6d55f11b3237b6e6d4..92315b52b4436abdc9622393eea1eb5b4fe681fc 100644 (file)
@@ -1,6 +1,7 @@
        th.vsetvl a0, a1, a2
        th.vsetvli a0, a1, 0
        th.vsetvli a0, a1, 0x7ff
+       th.vsetvli a0, a1, e16,m2,d4
 
        th.vlb.v v4, (a0)
        th.vlb.v v4, 0(a0)
index 449cb78ee798d28791ff9accb8560d517ffe7ebf..adea7dbc794298d69df719175d3cf7640e43f9b1 100644 (file)
@@ -328,6 +328,15 @@ static inline unsigned int riscv_insn_length (insn_t insn)
 #define OP_MASK_VWD            0x1
 #define OP_SH_VWD              26
 
+#define OP_MASK_XTHEADVLMUL    0x3
+#define OP_SH_XTHEADVLMUL      0
+#define OP_MASK_XTHEADVSEW     0x7
+#define OP_SH_XTHEADVSEW       2
+#define OP_MASK_XTHEADVEDIV    0x3
+#define OP_SH_XTHEADVEDIV      5
+#define OP_MASK_XTHEADVTYPE_RES        0xf
+#define OP_SH_XTHEADVTYPE_RES  7
+
 #define NVECR 32
 #define NVECM 1
 
@@ -595,6 +604,8 @@ extern const char * const riscv_vsew[8];
 extern const char * const riscv_vlmul[8];
 extern const char * const riscv_vta[2];
 extern const char * const riscv_vma[2];
+extern const char * const riscv_th_vlen[4];
+extern const char * const riscv_th_vediv[4];
 extern const char * const riscv_fli_symval[32];
 extern const float riscv_fli_numval[32];
 
index a511ccb6d0774d08eee5f61ce6a27fd6c63cee1a..3019b9a5130f2f8e877026e3a8217f382ed93743 100644 (file)
@@ -653,6 +653,28 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
                bool sign;
                switch (*++oparg)
                  {
+                 case 'V':
+                  ++oparg;
+                  if (*oparg != 'c')
+                     goto undefined_modifier;
+
+                   int imm = (*oparg == 'b') ? EXTRACT_RVV_VB_IMM (l)
+                                             : EXTRACT_RVV_VC_IMM (l);
+                   unsigned int imm_vediv = EXTRACT_OPERAND (XTHEADVEDIV, imm);
+                   unsigned int imm_vlmul = EXTRACT_OPERAND (XTHEADVLMUL, imm);
+                   unsigned int imm_vsew = EXTRACT_OPERAND (XTHEADVSEW, imm);
+                   unsigned int imm_vtype_res
+                     = EXTRACT_OPERAND (XTHEADVTYPE_RES, imm);
+                   if (imm_vsew < ARRAY_SIZE (riscv_vsew)
+                       && imm_vlmul < ARRAY_SIZE (riscv_th_vlen)
+                       && imm_vediv < ARRAY_SIZE (riscv_th_vediv)
+                       && ! imm_vtype_res)
+                     print (info->stream, dis_style_text, "%s,%s,%s",
+                            riscv_vsew[imm_vsew], riscv_th_vlen[imm_vlmul],
+                            riscv_th_vediv[imm_vediv]);
+                   else
+                     print (info->stream, dis_style_immediate, "%d", imm);
+                   break;
                  case 'l': /* Integer immediate, literal.  */
                    oparg++;
                    while (*oparg && *oparg != ',')
index af19a4ecd5996a469997871767d1d417314ee633..fdd05ac75dc15ca38f17caa34b2f6e6229fc9300 100644 (file)
@@ -110,6 +110,18 @@ const char * const riscv_vma[2] =
   "mu", "ma"
 };
 
+/* XTheadVector, List of vsetvli vlmul constants.  */
+const char * const riscv_th_vlen[4] =
+{
+    "m1", "m2", "m4", "m8"
+};
+
+/* XTheadVector, List of vsetvli vediv constants.  */
+const char * const riscv_th_vediv[4] =
+{
+    "d1", "d2", "d4", "d8"
+};
+
 /* The FLI.[HSDQ] symbolic constants (NULL for numeric constant).  */
 const char * const riscv_fli_symval[32] =
 {
@@ -2236,7 +2248,7 @@ const struct riscv_opcode riscv_opcodes[] =
 
 /* Vendor-specific (T-Head) XTheadVector instructions.  */
 {"th.vsetvl",     0, INSN_CLASS_XTHEADVECTOR,  "d,s,t", MATCH_VSETVL, MASK_VSETVL, match_opcode, 0},
-{"th.vsetvli",    0, INSN_CLASS_XTHEADVECTOR,  "d,s,Vc", MATCH_VSETVLI, MASK_VSETVLI, match_opcode, 0},
+{"th.vsetvli",    0, INSN_CLASS_XTHEADVECTOR,  "d,s,XtVc", MATCH_VSETVLI, MASK_VSETVLI, match_opcode, 0},
 {"th.vlb.v",      0, INSN_CLASS_XTHEADVECTOR,  "Vd,0(s)Vm", MATCH_TH_VLBV, MASK_TH_VLBV, match_opcode, INSN_DREF },
 {"th.vlh.v",      0, INSN_CLASS_XTHEADVECTOR,  "Vd,0(s)Vm", MATCH_TH_VLHV, MASK_TH_VLHV, match_opcode, INSN_DREF },
 {"th.vlw.v",      0, INSN_CLASS_XTHEADVECTOR,  "Vd,0(s)Vm", MATCH_TH_VLWV, MASK_TH_VLWV, match_opcode, INSN_DREF },