RISC-V: Supports Zcb extension.
authorJiawei <jiawei@iscas.ac.cn>
Wed, 12 Jul 2023 12:40:36 +0000 (20:40 +0800)
committerNelson Chu <nelson@rivosinc.com>
Tue, 18 Jul 2023 03:45:58 +0000 (11:45 +0800)
This patch support Zcb extension, contains new compressed instructions,
some instructions depend on other existed extension, like 'zba', 'zbb'
and 'zmmul'.  Zcb also imply Zca extension to enable the compressing
features.

Co-Authored by: Charlie Keaney <charlie.keaney@embecosm.com>
Co-Authored by: Mary Bennett <mary.bennett@embecosm.com>
Co-Authored by: Nandni Jamnadas <nandni.jamnadas@embecosm.com>
Co-Authored by: Sinan Lin <sinan.lin@linux.alibaba.com>
Co-Authored by: Simon Cook <simon.cook@embecosm.com>
Co-Authored by: Shihua Liao <shihua@iscas.ac.cn>
Co-Authored by: Yulong Shi <yulong@iscas.ac.cn>

bfd/ChangeLog:

        * elfxx-riscv.c (riscv_multi_subset_supports): New extension.
        (riscv_multi_subset_supports_ext): Ditto.

gas/ChangeLog:

        * config/tc-riscv.c (validate_riscv_insn): New operators.
        (riscv_ip): Ditto.
        * testsuite/gas/riscv/zcb.d: New test.
        * testsuite/gas/riscv/zcb.s: New test.

include/ChangeLog:

        * opcode/riscv-opc.h (MATCH_C_LBU): New opcode.
        (MASK_C_LBU): New mask.
        (MATCH_C_LHU): New opcode.
        (MASK_C_LHU): New mask.
        (MATCH_C_LH): New opcode.
        (MASK_C_LH): New mask.
        (MATCH_C_SB): New opcode.
        (MASK_C_SB): New mask.
        (MATCH_C_SH): New opcode.
        (MASK_C_SH): New mask.
        (MATCH_C_ZEXT_B): New opcode.
        (MASK_C_ZEXT_B): New mask.
        (MATCH_C_SEXT_B): New opcode.
        (MASK_C_SEXT_B): New mask.
        (MATCH_C_ZEXT_H): New opcode.
        (MASK_C_ZEXT_H): New mask.
        (MATCH_C_SEXT_H): New opcode.
        (MASK_C_SEXT_H): New mask.
        (MATCH_C_ZEXT_W): New opcode.
        (MASK_C_ZEXT_W): New mask.
        (MATCH_C_NOT): New opcode.
        (MASK_C_NOT): New mask.
        (MATCH_C_MUL): New opcode.
        (MASK_C_MUL): New mask.
        (DECLARE_INSN): New opcode.
        * opcode/riscv.h (EXTRACT_ZCB_BYTE_UIMM): New inline func.
        (EXTRACT_ZCB_HALFWORD_UIMM): Ditto.
        (ENCODE_ZCB_BYTE_UIMM): Ditto.
        (ENCODE_ZCB_HALFWORD_UIMM): Ditto.
        (VALID_ZCB_BYTE_UIMM): Ditto.
        (VALID_ZCB_HALFWORD_UIMM): Ditto.
        (enum riscv_insn_class): New extension class.

opcodes/ChangeLog:

        * riscv-dis.c (print_insn_args): New operators.
        * riscv-opc.c: New instructions.

bfd/elfxx-riscv.c
gas/config/tc-riscv.c
gas/testsuite/gas/riscv/zcb.d [new file with mode: 0644]
gas/testsuite/gas/riscv/zcb.s [new file with mode: 0644]
include/opcode/riscv-opc.h
include/opcode/riscv.h
opcodes/riscv-dis.c
opcodes/riscv-opc.c

index 86351872e048e260decda3ad0216f39c41cf2564..ee96608358e82b1e7dbe43805ba1e23d9cac8593 100644 (file)
@@ -1173,6 +1173,7 @@ static struct riscv_implicit_subset riscv_implicit_subsets[] =
   {"zvksc", "zvbc",    check_implicit_always},
   {"zcf", "zca",       check_implicit_always},
   {"zcd", "zca",       check_implicit_always},
+  {"zcb", "zca",       check_implicit_always},
   {"smaia", "ssaia",           check_implicit_always},
   {"smstateen", "ssstateen",   check_implicit_always},
   {"smepmp", "zicsr",          check_implicit_always},
@@ -1307,6 +1308,7 @@ static struct riscv_supported_ext riscv_supported_std_z_ext[] =
   {"zvl65536b",                ISA_SPEC_CLASS_DRAFT,           1, 0,  0 },
   {"ztso",             ISA_SPEC_CLASS_DRAFT,           0, 1,  0 },
   {"zca",              ISA_SPEC_CLASS_DRAFT,           1, 0,  0 },
+  {"zcb",              ISA_SPEC_CLASS_DRAFT,           1, 0,  0 },
   {"zcf",              ISA_SPEC_CLASS_DRAFT,           1, 0,  0 },
   {"zcd",              ISA_SPEC_CLASS_DRAFT,           1, 0,  0 },
   {NULL, 0, 0, 0, 0}
@@ -2494,6 +2496,17 @@ riscv_multi_subset_supports (riscv_parse_subset_t *rps,
       return riscv_subset_supports (rps, "zvksed");
     case INSN_CLASS_ZVKSH:
       return riscv_subset_supports (rps, "zvksh");
+    case INSN_CLASS_ZCB:
+      return riscv_subset_supports (rps, "zcb");
+    case INSN_CLASS_ZCB_AND_ZBB:
+      return (riscv_subset_supports (rps, "zcb")
+             && riscv_subset_supports (rps, "zbb"));
+    case INSN_CLASS_ZCB_AND_ZBA:
+      return (riscv_subset_supports (rps, "zcb")
+             && riscv_subset_supports (rps, "zba"));
+    case INSN_CLASS_ZCB_AND_ZMMUL:
+      return (riscv_subset_supports (rps, "zcb")
+             && riscv_subset_supports (rps, "zmmul"));
     case INSN_CLASS_SVINVAL:
       return riscv_subset_supports (rps, "svinval");
     case INSN_CLASS_H:
@@ -2702,6 +2715,14 @@ riscv_multi_subset_supports_ext (riscv_parse_subset_t *rps,
       return _("zvksed");
     case INSN_CLASS_ZVKSH:
       return _("zvksh");
+    case INSN_CLASS_ZCB:
+      return "zcb";
+    case INSN_CLASS_ZCB_AND_ZBA:
+      return _("zcb' and `zba");
+    case INSN_CLASS_ZCB_AND_ZBB:
+      return _("zcb' and `zbb");
+    case INSN_CLASS_ZCB_AND_ZMMUL:
+      return _("zcb' and `zmmul', or `zcb' and `m");
     case INSN_CLASS_SVINVAL:
       return "svinval";
     case INSN_CLASS_H:
index 8c23c6abae79b4f5152ae0e5e08c8aca5e4a8f4e..80c14a3cd2211e60da9811e7e997498214647058 100644 (file)
@@ -1426,6 +1426,18 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length)
                  goto unknown_validate_operand;
                }
              break;
+           case 'c':
+             switch (*++oparg)
+               {
+               /* byte immediate operators, load/store byte insns.  */
+               case 'h': used_bits |= ENCODE_ZCB_HALFWORD_UIMM (-1U); break;
+               /* halfword immediate operators, load/store halfword insns.  */
+               case 'b': used_bits |= ENCODE_ZCB_BYTE_UIMM (-1U); break;
+               case 'f': break;
+               default:
+                 goto unknown_validate_operand;
+               }
+             break;
            default:
              goto unknown_validate_operand;
            }
@@ -3559,6 +3571,47 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
                      goto unknown_riscv_ip_operand;
                    }
                  break;
+
+               case 'c':
+                 switch (*++oparg)
+                   {
+                   case 'h': /* Immediate field for c.lh/c.lhu/c.sh.  */
+                     /* Handle cases, such as c.sh rs2', (rs1').  */
+                     if (riscv_handle_implicit_zero_offset (imm_expr, asarg))
+                       continue;
+                     if (my_getSmallExpression (imm_expr, imm_reloc, asarg, p)
+                         || imm_expr->X_op != O_constant
+                         || !VALID_ZCB_HALFWORD_UIMM ((valueT) imm_expr->X_add_number))
+                       break;
+                     ip->insn_opcode |= ENCODE_ZCB_HALFWORD_UIMM (imm_expr->X_add_number);
+                     goto rvc_imm_done;
+
+                   case 'b': /* Immediate field for c.lbu/c.sb.  */
+                     /* Handle cases, such as c.lbu rd', (rs1').  */
+                     if (riscv_handle_implicit_zero_offset (imm_expr, asarg))
+                       continue;
+                     if (my_getSmallExpression (imm_expr, imm_reloc, asarg, p)
+                         || imm_expr->X_op != O_constant
+                         || !VALID_ZCB_BYTE_UIMM ((valueT) imm_expr->X_add_number))
+                       break;
+                     ip->insn_opcode |= ENCODE_ZCB_BYTE_UIMM (imm_expr->X_add_number);
+                     goto rvc_imm_done;
+
+                   case 'f': /* Operand for matching immediate 255.  */
+                     if (my_getSmallExpression (imm_expr, imm_reloc, asarg, p)
+                         || imm_expr->X_op != O_constant
+                         || imm_expr->X_add_number != 255)
+                       break;
+                     /* This operand is used for matching immediate 255, and
+                        we do not write anything to encoding by this operand.  */
+                     asarg = expr_parse_end;
+                     imm_expr->X_op = O_absent;
+                     continue;
+
+                   default:
+                     goto unknown_riscv_ip_operand;
+                   }
+                 break;
                default:
                  goto unknown_riscv_ip_operand;
                }
diff --git a/gas/testsuite/gas/riscv/zcb.d b/gas/testsuite/gas/riscv/zcb.d
new file mode 100644 (file)
index 0000000..26a122b
--- /dev/null
@@ -0,0 +1,32 @@
+#as: -march=rv64im_zba_zbb_zcb
+#objdump: -d -Mno-aliases
+
+.*:[   ]+file format .*
+
+Disassembly of section .text:
+
+0+000 <target>:
+[      ]+[0-9a-f]+:[   ]+8020[         ]+c.lbu[        ]+s0,2\(s0\)
+[      ]+[0-9a-f]+:[   ]+8380[         ]+c.lbu[        ]+s0,0\(a5\)
+[      ]+[0-9a-f]+:[   ]+8420[         ]+c.lhu[        ]+s0,2\(s0\)
+[      ]+[0-9a-f]+:[   ]+8780[         ]+c.lhu[        ]+s0,0\(a5\)
+[      ]+[0-9a-f]+:[   ]+8460[         ]+c.lh[         ]+s0,2\(s0\)
+[      ]+[0-9a-f]+:[   ]+87c0[         ]+c.lh[         ]+s0,0\(a5\)
+[      ]+[0-9a-f]+:[   ]+8820[         ]+c.sb[         ]+s0,2\(s0\)
+[      ]+[0-9a-f]+:[   ]+8b80[         ]+c.sb[         ]+s0,0\(a5\)
+[      ]+[0-9a-f]+:[   ]+8c20[         ]+c.sh[         ]+s0,2\(s0\)
+[      ]+[0-9a-f]+:[   ]+8f80[         ]+c.sh[         ]+s0,0\(a5\)
+[      ]+[0-9a-f]+:[   ]+9c61[         ]+c.zext.b[     ]+s0
+[      ]+[0-9a-f]+:[   ]+9fe1[         ]+c.zext.b[     ]+a5
+[      ]+[0-9a-f]+:[   ]+9c65[         ]+c.sext.b[     ]+s0
+[      ]+[0-9a-f]+:[   ]+9fe5[         ]+c.sext.b[     ]+a5
+[      ]+[0-9a-f]+:[   ]+9c69[         ]+c.zext.h[     ]+s0
+[      ]+[0-9a-f]+:[   ]+9fe9[         ]+c.zext.h[     ]+a5
+[      ]+[0-9a-f]+:[   ]+9c6d[         ]+c.sext.h[     ]+s0
+[      ]+[0-9a-f]+:[   ]+9fed[         ]+c.sext.h[     ]+a5
+[      ]+[0-9a-f]+:[   ]+9c71[         ]+c.zext.w[     ]+s0
+[      ]+[0-9a-f]+:[   ]+9ff1[         ]+c.zext.w[     ]+a5
+[      ]+[0-9a-f]+:[   ]+9c75[         ]+c.not[        ]+s0
+[      ]+[0-9a-f]+:[   ]+9ff5[         ]+c.not[        ]+a5
+[      ]+[0-9a-f]+:[   ]+9c5d[         ]+c.mul[        ]+s0,a5
+[      ]+[0-9a-f]+:[   ]+9cd1[         ]+c.mul[        ]+s1,a2
diff --git a/gas/testsuite/gas/riscv/zcb.s b/gas/testsuite/gas/riscv/zcb.s
new file mode 100644 (file)
index 0000000..2e70ab2
--- /dev/null
@@ -0,0 +1,25 @@
+target:
+       lbu x8,2(x8)
+       c.lbu x8,(x15)
+       lhu x8,2(x8)
+       c.lhu x8,(x15)
+       lh x8,2(x8)
+       c.lh x8,(x15)
+       sb x8,2(x8)
+       c.sb x8,(x15)
+       sh x8,2(x8)
+       c.sh x8,(x15)
+       zext.b x8,x8
+       c.zext.b x15
+       sext.b x8,x8
+       c.sext.b x15
+       zext.h x8,x8
+       c.zext.h x15
+       sext.h x8,x8
+       c.sext.h x15
+       zext.w x8,x8
+       c.zext.w x15
+       not x8,x8
+       c.not x15
+       mul x8,x8,x15
+       c.mul x9,x12
index 90f441537501dafdf1ee9b683a1e89e90a5f706c..53f5f2005085ebb8027d5bc15ffd14e7de075291 100644 (file)
 #define MASK_VSM3C_VI 0xfe00707f
 #define MATCH_VSM3ME_VV 0x82002077
 #define MASK_VSM3ME_VV 0xfe00707f
+/* Zcb instructions.  */
+#define MATCH_C_LBU 0x8000
+#define MASK_C_LBU 0xfc03
+#define MATCH_C_LHU 0x8400
+#define MASK_C_LHU 0xfc43
+#define MATCH_C_LH 0x8440
+#define MASK_C_LH 0xfc43
+#define MATCH_C_SB 0x8800
+#define MASK_C_SB 0xfc03
+#define MATCH_C_SH 0x8c00
+#define MASK_C_SH 0xfc43
+#define MATCH_C_ZEXT_B 0x9c61
+#define MASK_C_ZEXT_B 0xfc7f
+#define MATCH_C_SEXT_B 0x9c65
+#define MASK_C_SEXT_B 0xfc7f
+#define MATCH_C_ZEXT_H 0x9c69
+#define MASK_C_ZEXT_H 0xfc7f
+#define MATCH_C_SEXT_H 0x9c6d
+#define MASK_C_SEXT_H 0xfc7f
+#define MATCH_C_ZEXT_W 0x9c71
+#define MASK_C_ZEXT_W 0xfc7f
+#define MATCH_C_NOT 0x9c75
+#define MASK_C_NOT 0xfc7f
+#define MATCH_C_MUL 0x9c41
+#define MASK_C_MUL 0xfc63
 /* Svinval instruction.  */
 #define MATCH_SINVAL_VMA 0x16000073
 #define MASK_SINVAL_VMA 0xfe007fff
@@ -3367,6 +3392,19 @@ DECLARE_INSN(vsm4r_vv, MATCH_VSM4R_VV, MASK_VSM4R_VV)
 /* Zvksh instructions.  */
 DECLARE_INSN(vsm3c_vi, MATCH_VSM3C_VI, MASK_VSM3C_VI)
 DECLARE_INSN(vsm3me_vv, MATCH_VSM3ME_VV, MASK_VSM3ME_VV)
+/* Zcb instructions.  */
+DECLARE_INSN(c_sext_b, MATCH_C_SEXT_B, MASK_C_SEXT_B)
+DECLARE_INSN(c_sext_h, MATCH_C_SEXT_H, MASK_C_SEXT_H)
+DECLARE_INSN(c_zext_b, MATCH_C_ZEXT_B, MASK_C_ZEXT_B)
+DECLARE_INSN(c_zext_h, MATCH_C_ZEXT_H, MASK_C_ZEXT_H)
+DECLARE_INSN(c_zext_w, MATCH_C_ZEXT_W, MASK_C_ZEXT_W)
+DECLARE_INSN(c_mul, MATCH_C_MUL, MASK_C_MUL)
+DECLARE_INSN(c_not, MATCH_C_NOT, MASK_C_NOT)
+DECLARE_INSN(c_lbu, MATCH_C_LBU, MASK_C_LBU)
+DECLARE_INSN(c_lhu, MATCH_C_LHU, MASK_C_LHU)
+DECLARE_INSN(c_lh, MATCH_C_LH, MASK_C_LH)
+DECLARE_INSN(c_sb, MATCH_C_SB, MASK_C_SB)
+DECLARE_INSN(c_sh, MATCH_C_SH, MASK_C_SH)
 /* Vendor-specific (T-Head) XTheadBa instructions.  */
 DECLARE_INSN(th_addsl, MATCH_TH_ADDSL, MASK_TH_ADDSL)
 /* Vendor-specific (T-Head) XTheadBb instructions.  */
index 739d6dafae9db87997055787a04c32c8f02d882a..808f36573030f88ad2d0e12f16a1ff7caa0274e1 100644 (file)
@@ -108,6 +108,10 @@ static inline unsigned int riscv_insn_length (insn_t insn)
   (RV_X(x, 20, 10))
 #define EXTRACT_RVV_VC_IMM(x) \
   (RV_X(x, 20, 11))
+#define EXTRACT_ZCB_BYTE_UIMM(x) \
+  (RV_X(x, 6, 1) | (RV_X(x, 5, 1) << 1))
+#define EXTRACT_ZCB_HALFWORD_UIMM(x) \
+  (RV_X(x, 5, 1) << 1)
 
 #define ENCODE_ITYPE_IMM(x) \
   (RV_X(x, 0, 12) << 20)
@@ -155,6 +159,10 @@ static inline unsigned int riscv_insn_length (insn_t insn)
   (RV_X(x, 0, 11) << 20)
 #define ENCODE_RVV_VI_UIMM6(x) \
   (RV_X(x, 0, 5) << 15 | RV_X(x, 5, 1) << 26)
+#define ENCODE_ZCB_BYTE_UIMM(x) \
+  ((RV_X(x, 0, 1) << 6) | (RV_X(x, 1, 1) << 5))
+#define ENCODE_ZCB_HALFWORD_UIMM(x) \
+  (RV_X(x, 1, 1) << 5)
 
 #define VALID_ITYPE_IMM(x) (EXTRACT_ITYPE_IMM(ENCODE_ITYPE_IMM(x)) == (x))
 #define VALID_STYPE_IMM(x) (EXTRACT_STYPE_IMM(ENCODE_STYPE_IMM(x)) == (x))
@@ -180,6 +188,8 @@ static inline unsigned int riscv_insn_length (insn_t insn)
 #define VALID_CJTYPE_IMM(x) (EXTRACT_CJTYPE_IMM(ENCODE_CJTYPE_IMM(x)) == (x))
 #define VALID_RVV_VB_IMM(x) (EXTRACT_RVV_VB_IMM(ENCODE_RVV_VB_IMM(x)) == (x))
 #define VALID_RVV_VC_IMM(x) (EXTRACT_RVV_VC_IMM(ENCODE_RVV_VC_IMM(x)) == (x))
+#define VALID_ZCB_BYTE_UIMM(x) (EXTRACT_ZCB_BYTE_UIMM(ENCODE_ZCB_BYTE_UIMM(x)) == (x))
+#define VALID_ZCB_HALFWORD_UIMM(x) (EXTRACT_ZCB_HALFWORD_UIMM(ENCODE_ZCB_HALFWORD_UIMM(x)) == (x))
 
 #define RISCV_RTYPE(insn, rd, rs1, rs2) \
   ((MATCH_ ## insn) | ((rd) << OP_SH_RD) | ((rs1) << OP_SH_RS1) | ((rs2) << OP_SH_RS2))
@@ -421,6 +431,10 @@ enum riscv_insn_class
   INSN_CLASS_ZVKNHA_OR_ZVKNHB,
   INSN_CLASS_ZVKSED,
   INSN_CLASS_ZVKSH,
+  INSN_CLASS_ZCB,
+  INSN_CLASS_ZCB_AND_ZBA,
+  INSN_CLASS_ZCB_AND_ZBB,
+  INSN_CLASS_ZCB_AND_ZMMUL,
   INSN_CLASS_SVINVAL,
   INSN_CLASS_ZICBOM,
   INSN_CLASS_ZICBOP,
index 827d9b67437dbe860aa7a8947c57596030ee9556..2826248f8afa7d266d84776fb925204532bc4255 100644 (file)
@@ -614,6 +614,20 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
                    goto undefined_modifier;
                  }
                break;
+             case 'c': /* Zcb extension 16 bits length instruction fields. */
+               switch (*++oparg)
+                 {
+                 case 'b':
+                   print (info->stream, dis_style_immediate, "%d",
+                     (int)EXTRACT_ZCB_BYTE_UIMM (l));
+                   break;
+                 case 'h':
+                   print (info->stream, dis_style_immediate, "%d",
+                     (int)EXTRACT_ZCB_HALFWORD_UIMM (l));
+                   break;
+                 default: break;
+                 }
+               break;
              default:
                goto undefined_modifier;
              }
index 533e3f4a0790fde360de43219b5a1e464339b055..6a854736fec0b30a7598cf31f9702e548772e9cc 100644 (file)
@@ -380,12 +380,14 @@ const struct riscv_opcode riscv_opcodes[] =
 {"mv",          0, INSN_CLASS_I, "d,s",       MATCH_ADDI, MASK_ADDI|MASK_IMM, match_opcode, INSN_ALIAS },
 {"move",        0, INSN_CLASS_C, "d,CV",      MATCH_C_MV, MASK_C_MV, match_c_add, INSN_ALIAS },
 {"move",        0, INSN_CLASS_I, "d,s",       MATCH_ADDI, MASK_ADDI|MASK_IMM, match_opcode, INSN_ALIAS },
+{"zext.b",      0, INSN_CLASS_ZCB, "Cs,Cw",   MATCH_C_ZEXT_B, MASK_C_ZEXT_B, match_opcode, INSN_ALIAS },
 {"zext.b",      0, INSN_CLASS_I, "d,s",       MATCH_ANDI|ENCODE_ITYPE_IMM (255), MASK_ANDI | MASK_IMM, match_opcode, INSN_ALIAS },
 {"and",         0, INSN_CLASS_C, "Cs,Cw,Ct",  MATCH_C_AND, MASK_C_AND, match_opcode, INSN_ALIAS },
 {"and",         0, INSN_CLASS_C, "Cs,Ct,Cw",  MATCH_C_AND, MASK_C_AND, match_opcode, INSN_ALIAS },
 {"and",         0, INSN_CLASS_C, "Cs,Cw,Co",  MATCH_C_ANDI, MASK_C_ANDI, match_opcode, INSN_ALIAS },
 {"and",         0, INSN_CLASS_I, "d,s,t",     MATCH_AND, MASK_AND, match_opcode, 0 },
 {"and",         0, INSN_CLASS_I, "d,s,j",     MATCH_ANDI, MASK_ANDI, match_opcode, INSN_ALIAS },
+{"andi",        0, INSN_CLASS_ZCB, "Cs,Cw,Wcf",MATCH_C_ZEXT_B, MASK_C_ZEXT_B, match_opcode, INSN_ALIAS },
 {"andi",        0, INSN_CLASS_C, "Cs,Cw,Co",  MATCH_C_ANDI, MASK_C_ANDI, match_opcode, INSN_ALIAS },
 {"andi",        0, INSN_CLASS_I, "d,s,j",     MATCH_ANDI, MASK_ANDI, match_opcode, 0 },
 {"beqz",        0, INSN_CLASS_C, "Cs,Cp",     MATCH_C_BEQZ, MASK_C_BEQZ, match_opcode, INSN_ALIAS|INSN_CONDBRANCH },
@@ -449,16 +451,20 @@ const struct riscv_opcode riscv_opcodes[] =
 {"sub",         0, INSN_CLASS_I, "d,s,t",     MATCH_SUB, MASK_SUB, match_opcode, 0 },
 {"lb",          0, INSN_CLASS_I, "d,o(s)",    MATCH_LB, MASK_LB, match_opcode, INSN_DREF|INSN_1_BYTE },
 {"lb",          0, INSN_CLASS_I, "d,A",       0, (int) M_LB, match_never, INSN_MACRO },
+{"lbu",         0, INSN_CLASS_ZCB, "Ct,Wcb(Cs)", MATCH_C_LBU, MASK_C_LBU, match_opcode, INSN_ALIAS|INSN_DREF|INSN_1_BYTE },
 {"lbu",         0, INSN_CLASS_I, "d,o(s)",    MATCH_LBU, MASK_LBU, match_opcode, INSN_DREF|INSN_1_BYTE },
 {"lbu",         0, INSN_CLASS_I, "d,A",       0, (int) M_LBU, match_never, INSN_MACRO },
+{"lh",          0, INSN_CLASS_ZCB, "Ct,Wch(Cs)", MATCH_C_LH, MASK_C_LH, match_opcode, INSN_ALIAS|INSN_DREF|INSN_2_BYTE },
 {"lh",          0, INSN_CLASS_I, "d,o(s)",    MATCH_LH, MASK_LH, match_opcode, INSN_DREF|INSN_2_BYTE },
 {"lh",          0, INSN_CLASS_I, "d,A",       0, (int) M_LH, match_never, INSN_MACRO },
+{"lhu",         0, INSN_CLASS_ZCB, "Ct,Wch(Cs)", MATCH_C_LHU, MASK_C_LHU, match_opcode, INSN_ALIAS|INSN_DREF|INSN_2_BYTE },
 {"lhu",         0, INSN_CLASS_I, "d,o(s)",    MATCH_LHU, MASK_LHU, match_opcode, INSN_DREF|INSN_2_BYTE },
 {"lhu",         0, INSN_CLASS_I, "d,A",       0, (int) M_LHU, match_never, INSN_MACRO },
 {"lw",          0, INSN_CLASS_C, "d,Cm(Cc)",  MATCH_C_LWSP, MASK_C_LWSP, match_rd_nonzero, INSN_ALIAS|INSN_DREF|INSN_4_BYTE },
 {"lw",          0, INSN_CLASS_C, "Ct,Ck(Cs)", MATCH_C_LW, MASK_C_LW, match_opcode, INSN_ALIAS|INSN_DREF|INSN_4_BYTE },
 {"lw",          0, INSN_CLASS_I, "d,o(s)",    MATCH_LW, MASK_LW, match_opcode, INSN_DREF|INSN_4_BYTE },
 {"lw",          0, INSN_CLASS_I, "d,A",       0, (int) M_LW, match_never, INSN_MACRO },
+{"not",         0, INSN_CLASS_ZCB,  "Cs,Cw",  MATCH_C_NOT, MASK_C_NOT, match_opcode, INSN_ALIAS },
 {"not",         0, INSN_CLASS_I, "d,s",       MATCH_XORI|MASK_IMM, MASK_XORI|MASK_IMM, match_opcode, INSN_ALIAS },
 {"or",          0, INSN_CLASS_I, "d,s,j",     MATCH_ORI, MASK_ORI, match_opcode, INSN_ALIAS },
 {"or",          0, INSN_CLASS_C, "Cs,Cw,Ct",  MATCH_C_OR, MASK_C_OR, match_opcode, INSN_ALIAS },
@@ -478,8 +484,10 @@ const struct riscv_opcode riscv_opcodes[] =
 {"sltu",        0, INSN_CLASS_I, "d,s,j",     MATCH_SLTIU, MASK_SLTIU, match_opcode, INSN_ALIAS },
 {"sgt",         0, INSN_CLASS_I, "d,t,s",     MATCH_SLT, MASK_SLT, match_opcode, INSN_ALIAS },
 {"sgtu",        0, INSN_CLASS_I, "d,t,s",     MATCH_SLTU, MASK_SLTU, match_opcode, INSN_ALIAS },
+{"sb",          0, INSN_CLASS_ZCB, "Ct,Wcb(Cs)", MATCH_C_SB, MASK_C_SB, match_opcode, INSN_DREF|INSN_1_BYTE|INSN_ALIAS },
 {"sb",          0, INSN_CLASS_I, "t,q(s)",    MATCH_SB, MASK_SB, match_opcode, INSN_DREF|INSN_1_BYTE },
 {"sb",          0, INSN_CLASS_I, "t,A,s",     0, (int) M_SB, match_never, INSN_MACRO },
+{"sh",          0, INSN_CLASS_ZCB, "Ct,Wch(Cs)", MATCH_C_SH, MASK_C_SH, match_opcode, INSN_DREF|INSN_2_BYTE|INSN_ALIAS },
 {"sh",          0, INSN_CLASS_I, "t,q(s)",    MATCH_SH, MASK_SH, match_opcode, INSN_DREF|INSN_2_BYTE },
 {"sh",          0, INSN_CLASS_I, "t,A,s",     0, (int) M_SH, match_never, INSN_MACRO },
 {"sw",          0, INSN_CLASS_C, "CV,CM(Cc)", MATCH_C_SWSP, MASK_C_SWSP, match_opcode, INSN_ALIAS|INSN_DREF|INSN_4_BYTE },
@@ -626,6 +634,7 @@ const struct riscv_opcode riscv_opcodes[] =
 {"amominu.d.aqrl", 64, INSN_CLASS_A, "d,t,0(s)", MATCH_AMOMINU_D|MASK_AQRL, MASK_AMOMINU_D|MASK_AQRL, match_opcode, INSN_DREF|INSN_8_BYTE },
 
 /* Multiply/Divide instruction subset.  */
+{"mul",        0, INSN_CLASS_ZCB_AND_ZMMUL, "Cs,Cw,Ct",  MATCH_C_MUL, MASK_C_MUL, match_opcode, INSN_ALIAS },
 {"mul",        0, INSN_CLASS_ZMMUL, "d,s,t",     MATCH_MUL, MASK_MUL, match_opcode, 0 },
 {"mulh",       0, INSN_CLASS_ZMMUL, "d,s,t",     MATCH_MULH, MASK_MULH, match_opcode, 0 },
 {"mulhu",      0, INSN_CLASS_ZMMUL, "d,s,t",     MATCH_MULHU, MASK_MULHU, match_opcode, 0 },
@@ -1016,10 +1025,13 @@ const struct riscv_opcode riscv_opcodes[] =
 {"max",        0, INSN_CLASS_ZBB,  "d,s,t", MATCH_MAX, MASK_MAX, match_opcode, 0 },
 {"minu",       0, INSN_CLASS_ZBB,  "d,s,t", MATCH_MINU, MASK_MINU, match_opcode, 0 },
 {"maxu",       0, INSN_CLASS_ZBB,  "d,s,t", MATCH_MAXU, MASK_MAXU, match_opcode, 0 },
+{"sext.b",     0, INSN_CLASS_ZCB_AND_ZBB,  "Cs,Cw", MATCH_C_SEXT_B, MASK_C_SEXT_B, match_opcode, INSN_ALIAS },
 {"sext.b",     0, INSN_CLASS_ZBB,  "d,s",   MATCH_SEXT_B, MASK_SEXT_B, match_opcode, 0 },
 {"sext.b",     0, INSN_CLASS_I,         "d,s",   0, (int) M_SEXTB, match_never, INSN_MACRO },
+{"sext.h",     0, INSN_CLASS_ZCB_AND_ZBB,  "Cs,Cw", MATCH_C_SEXT_H, MASK_C_SEXT_H, match_opcode, INSN_ALIAS },
 {"sext.h",     0, INSN_CLASS_ZBB,  "d,s",   MATCH_SEXT_H, MASK_SEXT_H, match_opcode, 0 },
 {"sext.h",     0, INSN_CLASS_I,         "d,s",   0, (int) M_SEXTH, match_never, INSN_MACRO },
+{"zext.h",     0, INSN_CLASS_ZCB_AND_ZBB,  "Cs,Cw", MATCH_C_ZEXT_H, MASK_C_ZEXT_H, match_opcode, INSN_ALIAS },
 {"zext.h",    32, INSN_CLASS_ZBB,  "d,s",   MATCH_PACK, MASK_PACK | MASK_RS2, match_opcode, 0 },
 {"zext.h",    64, INSN_CLASS_ZBB,  "d,s",   MATCH_PACKW, MASK_PACKW | MASK_RS2, match_opcode, 0 },
 {"zext.h",     0, INSN_CLASS_I,         "d,s",   0, (int) M_ZEXTH, match_never, INSN_MACRO },
@@ -1055,6 +1067,7 @@ const struct riscv_opcode riscv_opcodes[] =
 {"sh1add.uw", 64, INSN_CLASS_ZBA,  "d,s,t", MATCH_SH1ADD_UW, MASK_SH1ADD_UW, match_opcode, 0 },
 {"sh2add.uw", 64, INSN_CLASS_ZBA,  "d,s,t", MATCH_SH2ADD_UW, MASK_SH2ADD_UW, match_opcode, 0 },
 {"sh3add.uw", 64, INSN_CLASS_ZBA,  "d,s,t", MATCH_SH3ADD_UW, MASK_SH3ADD_UW, match_opcode, 0 },
+{"zext.w",    64, INSN_CLASS_ZCB_AND_ZBA,  "Cs,Cw", MATCH_C_ZEXT_W, MASK_C_ZEXT_W, match_opcode, INSN_ALIAS },
 {"zext.w",    64, INSN_CLASS_ZBA,  "d,s",   MATCH_ADD_UW, MASK_ADD_UW | MASK_RS2, match_opcode, INSN_ALIAS },
 {"zext.w",    64, INSN_CLASS_I, "d,s",       0, (int) M_ZEXTW, match_never, INSN_MACRO },
 {"add.uw",    64, INSN_CLASS_ZBA,  "d,s,t", MATCH_ADD_UW, MASK_ADD_UW, match_opcode, 0 },
@@ -1939,6 +1952,21 @@ const struct riscv_opcode riscv_opcodes[] =
 {"vsm3c.vi",     0, INSN_CLASS_ZVKSH, "Vd,Vt,Vj", MATCH_VSM3C_VI, MASK_VSM3C_VI, match_opcode, 0},
 {"vsm3me.vv",    0, INSN_CLASS_ZVKSH, "Vd,Vt,Vs", MATCH_VSM3ME_VV, MASK_VSM3ME_VV, match_opcode, 0},
 
+/* ZCB instructions.  */
+{"c.lbu",      0, INSN_CLASS_ZCB, "Ct,Wcb(Cs)", MATCH_C_LBU, MASK_C_LBU, match_opcode, INSN_DREF|INSN_1_BYTE },
+{"c.lhu",      0, INSN_CLASS_ZCB, "Ct,Wch(Cs)", MATCH_C_LHU, MASK_C_LHU, match_opcode, INSN_DREF|INSN_2_BYTE },
+{"c.lh",       0, INSN_CLASS_ZCB, "Ct,Wch(Cs)", MATCH_C_LH, MASK_C_LH, match_opcode, INSN_DREF|INSN_2_BYTE },
+{"c.sb",       0, INSN_CLASS_ZCB, "Ct,Wcb(Cs)", MATCH_C_SB, MASK_C_SB, match_opcode, INSN_DREF|INSN_1_BYTE },
+{"c.sh",       0, INSN_CLASS_ZCB, "Ct,Wch(Cs)", MATCH_C_SH, MASK_C_SH, match_opcode, INSN_DREF|INSN_2_BYTE },
+{"c.not",      0, INSN_CLASS_ZCB, "Cs",  MATCH_C_NOT, MASK_C_NOT, match_opcode, 0 },
+{"c.mul",      0, INSN_CLASS_ZCB_AND_ZMMUL,   "Cs,Ct",  MATCH_C_MUL, MASK_C_MUL, match_opcode, 0 },
+{"c.sext.b",   0, INSN_CLASS_ZCB_AND_ZBB, "Cs",  MATCH_C_SEXT_B, MASK_C_SEXT_B, match_opcode, 0 },
+{"c.sext.h",   0, INSN_CLASS_ZCB_AND_ZBB, "Cs",  MATCH_C_SEXT_H, MASK_C_SEXT_H, match_opcode, 0 },
+{"c.zext.h",   0, INSN_CLASS_ZCB_AND_ZBB, "Cs",  MATCH_C_ZEXT_H, MASK_C_ZEXT_H, match_opcode, 0 },
+{"c.zext.w",  64, INSN_CLASS_ZCB_AND_ZBA, "Cs",  MATCH_C_ZEXT_W, MASK_C_ZEXT_W, match_opcode, 0 },
+{"c.zext.b",   0, INSN_CLASS_ZCB, "Cs",  MATCH_C_ZEXT_B, MASK_C_ZEXT_B, match_opcode, 0 },
+{"c.sext.w",  64, INSN_CLASS_ZCB, "d",  MATCH_C_ADDIW, MASK_C_ADDIW|MASK_RVC_IMM, match_rd_nonzero, INSN_ALIAS },
+
 /* Supervisor instructions.  */
 {"csrr",       0, INSN_CLASS_ZICSR, "d,E",   MATCH_CSRRS, MASK_CSRRS|MASK_RS1, match_opcode, INSN_ALIAS },
 {"csrw",       0, INSN_CLASS_ZICSR, "E,s",   MATCH_CSRRW, MASK_CSRRW|MASK_RD, match_opcode, INSN_ALIAS },