[PATCH v3 2/2] RISC-V: Support ".option [no]exact" assembler directives

Tsukasa OI research_trasio@irq.a4lg.com
Wed May 14 13:13:55 GMT 2025


From: Tsukasa OI <research_trasio@irq.a4lg.com>

This commit adds two assembler directives: ".option exact" and
".option noexact" (enable/disable the exact mode) as discussed in
<https://github.com/riscv-non-isa/riscv-asm-manual/pull/122> and
already implemented in LLVM.

When the exact mode is enabled,

1.  Linker relaxations are turned off,
2.  Instruction aliases that will change the encoding from the
    (likely non-alias) instruction with the same name are disabled
    (e.g. "addi" will never turn into "c.addi" even if optimizable) and
3.  Assembler relaxation of branch instructions are disabled
    (e.g. "blt" with a long offset will not turn into "bge + j").

The main purpose of this mode is to emit desired machine code as the
user writes, assuming the user knows constraints of their code.  So,
macros like "li" (known to be expanded into possibly complex sequences)
without single instruction encoding are not fully aware of this mode.

Currently, interactions between ".option relax/norelax" and
".option exact/noexact" are designed to be LLVM-compatible (i.e.
".option exact/noexact" imply ".option norelax/relax", respectively)
but considered flaky and strongly discouraged from using both.

cf. <https://github.com/llvm/llvm-project/pull/122483>

gas/ChangeLog:

	* config/tc-riscv.c (struct riscv_set_options): Add exact option.
	(RELAX_BRANCH_ENCODE): Encode exact option.
	(RELAX_BRANCH_EXACT): New predicate macro.
	(relaxed_branch_length): Handle exact mode cases.
	(append_insn): Pass exact option to RELAX_BRANCH_ENCODE.
	(riscv_ip): Skip instructions that would change the encoding
	when the exact mode is enabled.
	(s_riscv_option): Parse ".option exact" and ".option noexact"
	assembler directives.
	* doc/c-riscv.texi: Document new assembler directives.
	* testsuite/gas/riscv/exact.s: Test exact mode basics.
	* testsuite/gas/riscv/exact.d: Ditto.
	* testsuite/gas/riscv/exact-branch-local.s: Test conditional
	branches and unconditional jumps relative to a local symbol.
	* testsuite/gas/riscv/exact-branch-local-noexact.d: Ditto.
	* testsuite/gas/riscv/exact-branch-local-exact-ok.d: Ditto.
	* testsuite/gas/riscv/exact-branch-local-exact-fail.d: Ditto.
	* testsuite/gas/riscv/exact-branch-local-exact-fail.l: Ditto.
	* testsuite/gas/riscv/exact-branch-extern.s: Test conditional
	branches and unconditional jumps relative to an external symbol.
	* testsuite/gas/riscv/exact-branch-extern-noexact.d: Ditto.
	* testsuite/gas/riscv/exact-branch-extern-exact.d: Ditto.
	* testsuite/gas/riscv/no-relax-branch-offset-fail.s: Use exact
	mode to test various configurations and instructions.
	* testsuite/gas/riscv/no-relax-branch-offset-fail.d: Ditto.
	* testsuite/gas/riscv/no-relax-branch-offset-fail.l: Ditto.

include/ChangeLog:

	* opcode/riscv.h (INSN_NON_EXACT): New flag to represent aliases
	to reject on the exact mode.

opcodes/ChangeLog:

	* riscv-opc.c (riscv_opcodes): Add INSN_NON_EXACT flag to all
	instructions that should be rejected on the exact mode.
---
 gas/config/tc-riscv.c                         |  39 +++-
 gas/doc/c-riscv.texi                          |  13 ++
 .../gas/riscv/exact-branch-extern-exact.d     |  32 ++++
 .../gas/riscv/exact-branch-extern-noexact.d   |  50 ++++++
 gas/testsuite/gas/riscv/exact-branch-extern.s |  40 +++++
 .../gas/riscv/exact-branch-local-exact-fail.d |   3 +
 .../gas/riscv/exact-branch-local-exact-fail.l |  43 +++++
 .../gas/riscv/exact-branch-local-exact-ok.d   |  75 ++++++++
 .../gas/riscv/exact-branch-local-noexact.d    | 149 +++++++++++++++
 gas/testsuite/gas/riscv/exact-branch-local.s  | 138 ++++++++++++++
 gas/testsuite/gas/riscv/exact.d               |  15 ++
 gas/testsuite/gas/riscv/exact.s               |  11 ++
 .../gas/riscv/no-relax-branch-offset-fail.l   |   5 +-
 .../gas/riscv/no-relax-branch-offset-fail.s   |  11 +-
 include/opcode/riscv.h                        |   6 +
 opcodes/riscv-opc.c                           | 170 +++++++++---------
 16 files changed, 701 insertions(+), 99 deletions(-)
 create mode 100644 gas/testsuite/gas/riscv/exact-branch-extern-exact.d
 create mode 100644 gas/testsuite/gas/riscv/exact-branch-extern-noexact.d
 create mode 100644 gas/testsuite/gas/riscv/exact-branch-extern.s
 create mode 100644 gas/testsuite/gas/riscv/exact-branch-local-exact-fail.d
 create mode 100644 gas/testsuite/gas/riscv/exact-branch-local-exact-fail.l
 create mode 100644 gas/testsuite/gas/riscv/exact-branch-local-exact-ok.d
 create mode 100644 gas/testsuite/gas/riscv/exact-branch-local-noexact.d
 create mode 100644 gas/testsuite/gas/riscv/exact-branch-local.s
 create mode 100644 gas/testsuite/gas/riscv/exact.d
 create mode 100644 gas/testsuite/gas/riscv/exact.s

diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index bbe8887f3e8f..2a1a43212696 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -268,6 +268,7 @@ struct riscv_set_options
   int pic; /* Generate position-independent code.  */
   int rvc; /* Generate RVC code.  */
   int relax; /* Emit relocs the linker is allowed to relax.  */
+  int exact; /* Emit instructions without compression or relaxation.  */
   int arch_attr; /* Emit architecture and privileged elf attributes.  */
   int csr_check; /* Enable the CSR checking.  */
 };
@@ -277,6 +278,7 @@ static struct riscv_set_options riscv_opts =
   0, /* pic */
   0, /* rvc */
   1, /* relax */
+  0, /* exact */
   DEFAULT_RISCV_ATTR, /* arch_attr */
   0, /* csr_check */
 };
@@ -469,16 +471,18 @@ static bool explicit_priv_attr = false;
 static char *expr_parse_end;
 
 /* Macros for encoding relaxation state for RVC branches and far jumps.  */
-#define RELAX_BRANCH_ENCODE(uncond, rvc, length)	\
+#define RELAX_BRANCH_ENCODE(uncond, rvc, length, exact)	\
   ((relax_substateT) 					\
    (0xc0000000						\
     | ((uncond) ? 1 : 0)				\
     | ((rvc) ? 2 : 0)					\
-    | ((length) << 2)))
+    | ((length) << 2)					\
+    | ((exact) << 6)))
 #define RELAX_BRANCH_P(i) (((i) & 0xf0000000) == 0xc0000000)
 #define RELAX_BRANCH_LENGTH(i) (((i) >> 2) & 0xF)
 #define RELAX_BRANCH_RVC(i) (((i) & 2) != 0)
 #define RELAX_BRANCH_UNCOND(i) (((i) & 1) != 0)
+#define RELAX_BRANCH_EXACT(i) (((i) & 0x40) != 0)
 
 /* Is the given value a sign-extended 32-bit value?  */
 #define IS_SEXT_32BIT_NUM(x)						\
@@ -808,22 +812,25 @@ add_relaxed_insn (struct riscv_cl_insn *insn, int max_chars, int var,
 static unsigned
 relaxed_branch_length (fragS *fragp, asection *sec, int update)
 {
-  int jump, rvc, length = 8;
+  int jump, rvc, exact, length = 8;
 
   if (!fragp)
     return length;
 
   jump = RELAX_BRANCH_UNCOND (fragp->fr_subtype);
   rvc = RELAX_BRANCH_RVC (fragp->fr_subtype);
+  exact = RELAX_BRANCH_EXACT (fragp->fr_subtype);
   length = RELAX_BRANCH_LENGTH (fragp->fr_subtype);
 
   /* Assume jumps are in range; the linker will catch any that aren't.  */
   length = jump ? 4 : 8;
 
-  if (fragp->fr_symbol != NULL
-      && S_IS_DEFINED (fragp->fr_symbol)
-      && !S_IS_WEAK (fragp->fr_symbol)
-      && sec == S_GET_SEGMENT (fragp->fr_symbol))
+  if (exact)
+    length = rvc ? 2 : 4;
+  else if (fragp->fr_symbol != NULL
+	   && S_IS_DEFINED (fragp->fr_symbol)
+	   && !S_IS_WEAK (fragp->fr_symbol)
+	   && sec == S_GET_SEGMENT (fragp->fr_symbol))
     {
       offsetT val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset;
       bfd_vma rvc_range = jump ? RVC_JUMP_REACH : RVC_BRANCH_REACH;
@@ -838,7 +845,7 @@ relaxed_branch_length (fragS *fragp, asection *sec, int update)
     }
 
   if (update)
-    fragp->fr_subtype = RELAX_BRANCH_ENCODE (jump, rvc, length);
+    fragp->fr_subtype = RELAX_BRANCH_ENCODE (jump, rvc, length, exact);
 
   return length;
 }
@@ -1990,7 +1997,8 @@ append_insn (struct riscv_cl_insn *ip, expressionS *address_expr,
 	    }
 
 	  add_relaxed_insn (ip, worst_case, best_case,
-			    RELAX_BRANCH_ENCODE (j, best_case == 2, worst_case),
+			    RELAX_BRANCH_ENCODE (j, best_case == 2, worst_case,
+						 riscv_opts.exact),
 			    address_expr->X_add_symbol,
 			    address_expr->X_add_number);
 	  return;
@@ -2870,6 +2878,9 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
       if ((insn->xlen_requirement != 0) && (xlen != insn->xlen_requirement))
 	continue;
 
+      if (riscv_opts.exact && (insn->pinfo & INSN_NON_EXACT))
+	continue;
+
       if (!riscv_multi_subset_supports (&riscv_rps_as, insn->insn_class))
 	{
 	  error.missing_ext = riscv_multi_subset_supports_ext (&riscv_rps_as,
@@ -5089,6 +5100,16 @@ s_riscv_option (int x ATTRIBUTE_UNUSED)
     riscv_opts.relax = true;
   else if (strcmp (name, "norelax") == 0)
     riscv_opts.relax = false;
+  else if (strcmp (name, "exact") == 0)
+    {
+      riscv_opts.exact = true;
+      riscv_opts.relax = false;
+    }
+  else if (strcmp (name, "noexact") == 0)
+    {
+      riscv_opts.exact = false;
+      riscv_opts.relax = true;
+    }
   else if (strcmp (name, "csr-check") == 0)
     riscv_opts.csr_check = true;
   else if (strcmp (name, "no-csr-check") == 0)
diff --git a/gas/doc/c-riscv.texi b/gas/doc/c-riscv.texi
index 28ccfb26b4b0..974414eb3c89 100644
--- a/gas/doc/c-riscv.texi
+++ b/gas/doc/c-riscv.texi
@@ -210,6 +210,19 @@ Enables or disables relaxation.  The RISC-V assembler and linker
 opportunistically relax some code sequences, but sometimes this behavior is not
 desirable.
 
+@item exact
+@itemx noexact
+Enables or disables exact mode.  Not only the exact mode disables linker
+relaxations, it also disables automatic instruction compression and the branch
+relaxation (both optionally change instruction encodings and/or instruction
+count).  This mode is useful in some cases where the instruction sequences, as
+exactly written, are expected to be emitted.
+
+Note that, in the current implementation, @samp{.option exact} implies
+@samp{.option norelax} and @samp{.option noexact} implies @samp{.option relax}.
+Due to their flaky interactions, it is strongly discouraged to use both
+@samp{.option relax/norelax} and @samp{.option exact/noexact} in the same scope.
+
 @item csr-check
 @itemx no-csr-check
 Enables or disables the CSR checking.
diff --git a/gas/testsuite/gas/riscv/exact-branch-extern-exact.d b/gas/testsuite/gas/riscv/exact-branch-extern-exact.d
new file mode 100644
index 000000000000..71224fc42336
--- /dev/null
+++ b/gas/testsuite/gas/riscv/exact-branch-extern-exact.d
@@ -0,0 +1,32 @@
+#as: -march=rv32ic --defsym exact_mode=1
+#source: exact-branch-extern.s
+#objdump: -drw -Mno-aliases
+
+.*:     file format .*
+
+
+Disassembly of section \.text:
+
+0+ <\.text>:
+[ 	]+[0-9a-f]+:[ 	]+00b50063[ 	]+beq[ 	]+a0,a1,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_BRANCH[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+feb51ee3[ 	]+bne[ 	]+a0,a1,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_BRANCH[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+feb54ce3[ 	]+blt[ 	]+a0,a1,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_BRANCH[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+feb55ae3[ 	]+bge[ 	]+a0,a1,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_BRANCH[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+feb568e3[ 	]+bltu[ 	]+a0,a1,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_BRANCH[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+feb576e3[ 	]+bgeu[ 	]+a0,a1,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_BRANCH[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+d565[ 	]+c\.beqz[ 	]+a0,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_RVC_BRANCH[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+f17d[ 	]+c\.bnez[ 	]+a0,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_RVC_BRANCH[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+fea5c2e3[ 	]+blt[ 	]+a1,a0,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_BRANCH[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+fea5d0e3[ 	]+bge[ 	]+a1,a0,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_BRANCH[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+fca5eee3[ 	]+bltu[ 	]+a1,a0,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_BRANCH[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+fca5fce3[ 	]+bgeu[ 	]+a1,a0,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_BRANCH[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+fc050ae3[ 	]+beq[ 	]+a0,zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_BRANCH[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+fc0518e3[ 	]+bne[ 	]+a0,zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_BRANCH[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+fc0546e3[ 	]+blt[ 	]+a0,zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_BRANCH[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+fca044e3[ 	]+blt[ 	]+zero,a0,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_BRANCH[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+fca052e3[ 	]+bge[ 	]+zero,a0,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_BRANCH[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+fc0550e3[ 	]+bge[ 	]+a0,zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_BRANCH[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+0001[ 	]+.*
+[ 	]+[0-9a-f]+:[ 	]+fbbff56f[ 	]+jal[ 	]+a0,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+bf5d[ 	]+c\.j[ 	]+[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_RVC_JUMP[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+3f55[ 	]+c\.jal[ 	]+[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_RVC_JUMP[ 	]+ext
diff --git a/gas/testsuite/gas/riscv/exact-branch-extern-noexact.d b/gas/testsuite/gas/riscv/exact-branch-extern-noexact.d
new file mode 100644
index 000000000000..0c17b482380a
--- /dev/null
+++ b/gas/testsuite/gas/riscv/exact-branch-extern-noexact.d
@@ -0,0 +1,50 @@
+#as: -march=rv32ic
+#source: exact-branch-extern.s
+#objdump: -drw -Mno-aliases
+
+.*:     file format .*
+
+
+Disassembly of section \.text:
+
+0+ <\.text>:
+[ 	]+[0-9a-f]+:[ 	]+00b51463[ 	]+bne[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ffdff06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+00b50463[ 	]+beq[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ff5ff06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+00b55463[ 	]+bge[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+fedff06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+00b54463[ 	]+blt[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+fe5ff06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+00b57463[ 	]+bgeu[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+fddff06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+00b56463[ 	]+bltu[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+fd5ff06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+00051463[ 	]+bne[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+fcdff06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+00050463[ 	]+beq[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+fc5ff06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+00a5d463[ 	]+bge[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+fbdff06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+00a5c463[ 	]+blt[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+fb5ff06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+00a5f463[ 	]+bgeu[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+fadff06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+00a5e463[ 	]+bltu[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+fa5ff06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+00051463[ 	]+bne[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+f9dff06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+00050463[ 	]+beq[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+f95ff06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+00055463[ 	]+bge[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+f8dff06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+00a05463[ 	]+bge[ 	]+zero,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+f85ff06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+00a04463[ 	]+blt[ 	]+zero,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+f7dff06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+00054463[ 	]+blt[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+f75ff06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+0001[ 	]+.*
+[ 	]+[0-9a-f]+:[ 	]+f6fff56f[ 	]+jal[ 	]+a0,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+f6bff06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+ext
+[ 	]+[0-9a-f]+:[ 	]+f67ff0ef[ 	]+jal[ 	]+ra,[0-9a-f]+.*[0-9a-f]+:[ 	]+R_RISCV_JAL[ 	]+ext
diff --git a/gas/testsuite/gas/riscv/exact-branch-extern.s b/gas/testsuite/gas/riscv/exact-branch-extern.s
new file mode 100644
index 000000000000..04d05fdd42dd
--- /dev/null
+++ b/gas/testsuite/gas/riscv/exact-branch-extern.s
@@ -0,0 +1,40 @@
+.ifdef exact_mode
+	.option	exact
+.else
+	.option	noexact
+.endif
+	.extern	ext
+
+	## Conditional Branches
+
+	# Basic instructions
+	beq	a0, a1, ext
+	bne	a0, a1, ext
+	blt	a0, a1, ext
+	bge	a0, a1, ext
+	bltu	a0, a1, ext
+	bgeu	a0, a1, ext
+
+	# Compressed instructions
+	c.beqz	a0, ext
+	c.bnez	a0, ext
+
+	# Aliases
+	bgt	a0, a1, ext
+	ble	a0, a1, ext
+	bgtu	a0, a1, ext
+	bleu	a0, a1, ext
+	beqz	a0, ext
+	bnez	a0, ext
+	bltz	a0, ext
+	bgtz	a0, ext
+	blez	a0, ext
+	bgez	a0, ext
+
+	c.nop
+
+	## Unconditional Jumps (normal and compressed)
+
+	jal	a0, ext
+	c.j	ext
+	c.jal	ext	# RV32C only
diff --git a/gas/testsuite/gas/riscv/exact-branch-local-exact-fail.d b/gas/testsuite/gas/riscv/exact-branch-local-exact-fail.d
new file mode 100644
index 000000000000..cdf9203574af
--- /dev/null
+++ b/gas/testsuite/gas/riscv/exact-branch-local-exact-fail.d
@@ -0,0 +1,3 @@
+#as: -march=rv32ic --defsym exact_mode=1 --defsym long_branch=1
+#source: exact-branch-local.s
+#error_output: exact-branch-local-exact-fail.l
diff --git a/gas/testsuite/gas/riscv/exact-branch-local-exact-fail.l b/gas/testsuite/gas/riscv/exact-branch-local-exact-fail.l
new file mode 100644
index 000000000000..502648fdd217
--- /dev/null
+++ b/gas/testsuite/gas/riscv/exact-branch-local-exact-fail.l
@@ -0,0 +1,43 @@
+.*Assembler messages:
+.*:93: Error: offset \(\+4096\) is invalid for B-type immediate
+.*:94: Error: offset \(-4098\) is invalid for B-type immediate
+.*:95: Error: offset \(\+4096\) is invalid for B-type immediate
+.*:96: Error: offset \(-4098\) is invalid for B-type immediate
+.*:97: Error: offset \(\+4096\) is invalid for B-type immediate
+.*:98: Error: offset \(-4098\) is invalid for B-type immediate
+.*:99: Error: offset \(\+4096\) is invalid for B-type immediate
+.*:100: Error: offset \(-4098\) is invalid for B-type immediate
+.*:101: Error: offset \(\+4096\) is invalid for B-type immediate
+.*:102: Error: offset \(-4098\) is invalid for B-type immediate
+.*:103: Error: offset \(\+4096\) is invalid for B-type immediate
+.*:104: Error: offset \(-4098\) is invalid for B-type immediate
+.*:105: Error: offset \(\+4096\) is invalid for B-type immediate
+.*:106: Error: offset \(-4098\) is invalid for B-type immediate
+.*:107: Error: offset \(\+4096\) is invalid for B-type immediate
+.*:108: Error: offset \(-4098\) is invalid for B-type immediate
+.*:109: Error: offset \(\+4096\) is invalid for B-type immediate
+.*:110: Error: offset \(-4098\) is invalid for B-type immediate
+.*:111: Error: offset \(\+4096\) is invalid for B-type immediate
+.*:112: Error: offset \(-4098\) is invalid for B-type immediate
+.*:113: Error: offset \(\+4096\) is invalid for B-type immediate
+.*:114: Error: offset \(-4098\) is invalid for B-type immediate
+.*:115: Error: offset \(\+4096\) is invalid for B-type immediate
+.*:116: Error: offset \(-4098\) is invalid for B-type immediate
+.*:117: Error: offset \(\+4096\) is invalid for B-type immediate
+.*:118: Error: offset \(-4098\) is invalid for B-type immediate
+.*:119: Error: offset \(\+4096\) is invalid for B-type immediate
+.*:120: Error: offset \(-4098\) is invalid for B-type immediate
+.*:121: Error: offset \(\+4096\) is invalid for B-type immediate
+.*:122: Error: offset \(-4098\) is invalid for B-type immediate
+.*:123: Error: offset \(\+4096\) is invalid for B-type immediate
+.*:124: Error: offset \(-4098\) is invalid for B-type immediate
+.*:128: Error: offset \(\+256\) is invalid for CB-type immediate
+.*:129: Error: offset \(-258\) is invalid for CB-type immediate
+.*:130: Error: offset \(\+256\) is invalid for CB-type immediate
+.*:131: Error: offset \(-258\) is invalid for CB-type immediate
+.*:132: Error: offset \(\+1048576\) is invalid for J-type immediate
+.*:133: Error: offset \(-1048578\) is invalid for J-type immediate
+.*:134: Error: offset \(\+2048\) is invalid for CJ-type immediate
+.*:135: Error: offset \(-2050\) is invalid for CJ-type immediate
+.*:136: Error: offset \(\+2048\) is invalid for CJ-type immediate
+.*:137: Error: offset \(-2050\) is invalid for CJ-type immediate
diff --git a/gas/testsuite/gas/riscv/exact-branch-local-exact-ok.d b/gas/testsuite/gas/riscv/exact-branch-local-exact-ok.d
new file mode 100644
index 000000000000..c7f1c6e74f6c
--- /dev/null
+++ b/gas/testsuite/gas/riscv/exact-branch-local-exact-ok.d
@@ -0,0 +1,75 @@
+#as: -march=rv32ic --defsym exact_mode=1
+#source: exact-branch-local.s
+#objdump: -d -Mno-aliases
+
+.*:     file format .*
+
+
+Disassembly of section \.text:
+
+0+ <\.text>:
+[ 	]+[0-9a-f]+:[ 	]+00b50063[ 	]+beq[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00b51063[ 	]+bne[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00b54063[ 	]+blt[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00b55063[ 	]+bge[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00b56063[ 	]+bltu[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00b57063[ 	]+bgeu[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a5c063[ 	]+blt[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a5d063[ 	]+bge[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a5e063[ 	]+bltu[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a5f063[ 	]+bgeu[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00050063[ 	]+beq[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00051063[ 	]+bne[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00054063[ 	]+blt[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a04063[ 	]+blt[ 	]+zero,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a05063[ 	]+bge[ 	]+zero,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00055063[ 	]+bge[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+0e050f63[ 	]+beq[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+f00500e3[ 	]+beq[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+0e051f63[ 	]+bne[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+f00510e3[ 	]+bne[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7e050fe3[ 	]+beq[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80050063[ 	]+beq[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7e051fe3[ 	]+bne[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80051063[ 	]+bne[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7eb50fe3[ 	]+beq[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80b50063[ 	]+beq[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7eb51fe3[ 	]+bne[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80b51063[ 	]+bne[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7eb54fe3[ 	]+blt[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80b54063[ 	]+blt[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7eb55fe3[ 	]+bge[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80b55063[ 	]+bge[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7eb56fe3[ 	]+bltu[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80b56063[ 	]+bltu[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7eb57fe3[ 	]+bgeu[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80b57063[ 	]+bgeu[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7ea5cfe3[ 	]+blt[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80a5c063[ 	]+blt[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7ea5dfe3[ 	]+bge[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80a5d063[ 	]+bge[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7ea5efe3[ 	]+bltu[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80a5e063[ 	]+bltu[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7ea5ffe3[ 	]+bgeu[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80a5f063[ 	]+bgeu[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7e050fe3[ 	]+beq[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80050063[ 	]+beq[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7e051fe3[ 	]+bne[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80051063[ 	]+bne[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7e054fe3[ 	]+blt[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80054063[ 	]+blt[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7ea04fe3[ 	]+blt[ 	]+zero,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80a04063[ 	]+blt[ 	]+zero,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7ea05fe3[ 	]+bge[ 	]+zero,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80a05063[ 	]+bge[ 	]+zero,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7e055fe3[ 	]+bge[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80055063[ 	]+bge[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+0000056f[ 	]+jal[ 	]+a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+a001[ 	]+c\.j[ 	]+[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+2001[ 	]+c\.jal[ 	]+[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7ffff56f[ 	]+jal[ 	]+a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+8000056f[ 	]+jal[ 	]+a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+affd[ 	]+c\.j[ 	]+[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+b001[ 	]+c\.j[ 	]+[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+2ffd[ 	]+c\.jal[ 	]+[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+3001[ 	]+c\.jal[ 	]+[0-9a-f]+.*
diff --git a/gas/testsuite/gas/riscv/exact-branch-local-noexact.d b/gas/testsuite/gas/riscv/exact-branch-local-noexact.d
new file mode 100644
index 000000000000..a10af28b67e9
--- /dev/null
+++ b/gas/testsuite/gas/riscv/exact-branch-local-noexact.d
@@ -0,0 +1,149 @@
+#as: -march=rv32ic --defsym long_branch=1
+#source: exact-branch-local.s
+#objdump: -d -Mno-aliases
+
+.*:     file format .*
+
+
+Disassembly of section \.text:
+
+0+ <\.text>:
+[ 	]+[0-9a-f]+:[ 	]+00b50063[ 	]+beq[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00b51063[ 	]+bne[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00b54063[ 	]+blt[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00b55063[ 	]+bge[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00b56063[ 	]+bltu[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00b57063[ 	]+bgeu[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a5c063[ 	]+blt[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a5d063[ 	]+bge[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a5e063[ 	]+bltu[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a5f063[ 	]+bgeu[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+c101[ 	]+c\.beqz[ 	]+a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+e101[ 	]+c\.bnez[ 	]+a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00054063[ 	]+blt[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a04063[ 	]+blt[ 	]+zero,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a05063[ 	]+bge[ 	]+zero,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00055063[ 	]+bge[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+cd7d[ 	]+c\.beqz[ 	]+a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+d101[ 	]+c\.beqz[ 	]+a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ed7d[ 	]+c\.bnez[ 	]+a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+f101[ 	]+c\.bnez[ 	]+a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7e050fe3[ 	]+beq[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80050063[ 	]+beq[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7e051fe3[ 	]+bne[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80051063[ 	]+bne[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7eb50fe3[ 	]+beq[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80b50063[ 	]+beq[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7eb51fe3[ 	]+bne[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80b51063[ 	]+bne[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7eb54fe3[ 	]+blt[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80b54063[ 	]+blt[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7eb55fe3[ 	]+bge[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80b55063[ 	]+bge[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7eb56fe3[ 	]+bltu[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80b56063[ 	]+bltu[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7eb57fe3[ 	]+bgeu[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80b57063[ 	]+bgeu[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7ea5cfe3[ 	]+blt[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80a5c063[ 	]+blt[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7ea5dfe3[ 	]+bge[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80a5d063[ 	]+bge[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7ea5efe3[ 	]+bltu[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80a5e063[ 	]+bltu[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7ea5ffe3[ 	]+bgeu[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80a5f063[ 	]+bgeu[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7e050fe3[ 	]+beq[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80050063[ 	]+beq[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7e051fe3[ 	]+bne[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80051063[ 	]+bne[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7e054fe3[ 	]+blt[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80054063[ 	]+blt[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7ea04fe3[ 	]+blt[ 	]+zero,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80a04063[ 	]+blt[ 	]+zero,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7ea05fe3[ 	]+bge[ 	]+zero,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80a05063[ 	]+bge[ 	]+zero,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7e055fe3[ 	]+bge[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+80055063[ 	]+bge[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+0000056f[ 	]+jal[ 	]+a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+a001[ 	]+c\.j[ 	]+.*
+[ 	]+[0-9a-f]+:[ 	]+2001[ 	]+c\.jal[ 	]+.*
+[ 	]+[0-9a-f]+:[ 	]+7ffff56f[ 	]+jal[ 	]+a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+8000056f[ 	]+jal[ 	]+a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+affd[ 	]+c\.j[ 	]+.*
+[ 	]+[0-9a-f]+:[ 	]+b001[ 	]+c\.j[ 	]+.*
+[ 	]+[0-9a-f]+:[ 	]+2ffd[ 	]+c\.jal[ 	]+.*
+[ 	]+[0-9a-f]+:[ 	]+3001[ 	]+c\.jal[ 	]+.*
+[ 	]+[0-9a-f]+:[ 	]+00b51463[ 	]+bne[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7fd0006f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00b51463[ 	]+bne[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ffbfe06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00b50463[ 	]+beq[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7fd0006f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00b50463[ 	]+beq[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ffbfe06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00b55463[ 	]+bge[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7fd0006f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00b55463[ 	]+bge[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ffbfe06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00b54463[ 	]+blt[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7fd0006f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00b54463[ 	]+blt[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ffbfe06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00b57463[ 	]+bgeu[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7fd0006f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00b57463[ 	]+bgeu[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ffbfe06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00b56463[ 	]+bltu[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7fd0006f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00b56463[ 	]+bltu[ 	]+a0,a1,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ffbfe06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a5d463[ 	]+bge[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7fd0006f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a5d463[ 	]+bge[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ffbfe06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a5c463[ 	]+blt[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7fd0006f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a5c463[ 	]+blt[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ffbfe06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a5f463[ 	]+bgeu[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7fd0006f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a5f463[ 	]+bgeu[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ffbfe06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a5e463[ 	]+bltu[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7fd0006f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a5e463[ 	]+bltu[ 	]+a1,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ffbfe06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+e119[ 	]+c\.bnez[ 	]+a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7ff0006f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+e119[ 	]+c\.bnez[ 	]+a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ffdfe06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+c119[ 	]+c\.beqz[ 	]+a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7ff0006f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+c119[ 	]+c\.beqz[ 	]+a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ffdfe06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00055463[ 	]+bge[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7fd0006f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00055463[ 	]+bge[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ffbfe06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a05463[ 	]+bge[ 	]+zero,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7fd0006f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a05463[ 	]+bge[ 	]+zero,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ffbfe06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a04463[ 	]+blt[ 	]+zero,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7fd0006f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00a04463[ 	]+blt[ 	]+zero,a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ffbfe06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00054463[ 	]+blt[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7fd0006f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+00054463[ 	]+blt[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ffbfe06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+10050063[ 	]+beq[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ee050fe3[ 	]+beq[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+10051063[ 	]+bne[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ee051fe3[ 	]+bne[ 	]+a0,zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+8000056f[ 	]+jal[ 	]+a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+7ffff56f[ 	]+jal[ 	]+a0,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+0010006f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ffeff06f[ 	]+jal[ 	]+zero,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+001000ef[ 	]+jal[ 	]+ra,[0-9a-f]+.*
+[ 	]+[0-9a-f]+:[ 	]+ffeff0ef[ 	]+jal[ 	]+ra,[0-9a-f]+.*
diff --git a/gas/testsuite/gas/riscv/exact-branch-local.s b/gas/testsuite/gas/riscv/exact-branch-local.s
new file mode 100644
index 000000000000..5aeba3620258
--- /dev/null
+++ b/gas/testsuite/gas/riscv/exact-branch-local.s
@@ -0,0 +1,138 @@
+.ifdef exact_mode
+	.option	exact
+.else
+	.option	noexact
+.endif
+
+	## Conditional Branches
+
+	# Zero offset.
+	beq	a0, a1, .
+	bne	a0, a1, .
+	blt	a0, a1, .
+	bge	a0, a1, .
+	bltu	a0, a1, .
+	bgeu	a0, a1, .
+
+	# Zero offset (aliases).
+	bgt	a0, a1, .
+	ble	a0, a1, .
+	bgtu	a0, a1, .
+	bleu	a0, a1, .
+	beqz	a0, .
+	bnez	a0, .
+	bltz	a0, .
+	bgtz	a0, .
+	blez	a0, .
+	bgez	a0, .
+
+	# Offsets that c.b{ne,eq}z can represent.
+	beqz	a0, .+0x0fe
+	beqz	a0, .-0x100
+	bnez	a0, .+0x0fe
+	bnez	a0, .-0x100
+
+	# Offsets that c.b{ne,eq}z cannot represent but single b{ne,eq}z can.
+	beqz	a0, .+0x0ffe
+	beqz	a0, .-0x1000
+	bnez	a0, .+0x0ffe
+	bnez	a0, .-0x1000
+
+	# Offsets that single conditional branch instruction can represent.
+	beq	a0, a1, .+0x0ffe
+	beq	a0, a1, .-0x1000
+	bne	a0, a1, .+0x0ffe
+	bne	a0, a1, .-0x1000
+	blt	a0, a1, .+0x0ffe
+	blt	a0, a1, .-0x1000
+	bge	a0, a1, .+0x0ffe
+	bge	a0, a1, .-0x1000
+	bltu	a0, a1, .+0x0ffe
+	bltu	a0, a1, .-0x1000
+	bgeu	a0, a1, .+0x0ffe
+	bgeu	a0, a1, .-0x1000
+	bgt	a0, a1, .+0x0ffe
+	bgt	a0, a1, .-0x1000
+	ble	a0, a1, .+0x0ffe
+	ble	a0, a1, .-0x1000
+	bgtu	a0, a1, .+0x0ffe
+	bgtu	a0, a1, .-0x1000
+	bleu	a0, a1, .+0x0ffe
+	bleu	a0, a1, .-0x1000
+	beqz	a0, .+0x0ffe
+	beqz	a0, .-0x1000
+	bnez	a0, .+0x0ffe
+	bnez	a0, .-0x1000
+	bltz	a0, .+0x0ffe
+	bltz	a0, .-0x1000
+	bgtz	a0, .+0x0ffe
+	bgtz	a0, .-0x1000
+	blez	a0, .+0x0ffe
+	blez	a0, .-0x1000
+	bgez	a0, .+0x0ffe
+	bgez	a0, .-0x1000
+
+	## Unconditional Jumps (normal and compressed)
+
+	# Zero offset.
+	jal	a0, .
+	c.j	.
+	c.jal	.	# RV32C only
+
+	# Offsets that single jump instruction can represent.
+	jal	a0, .+0x0ffffe
+	jal	a0, .-0x100000
+	c.j	.+0x7fe
+	c.j	.-0x800
+	c.jal	.+0x7fe	# RV32C only
+	c.jal	.-0x800	# RV32C only
+
+.ifdef long_branch
+	# Offsets that single conditional branch instruction cannot represent.
+	# (should fail on the exact mode)
+	beq	a0, a1, .+0x0ffe+2
+	beq	a0, a1, .-0x1000-2
+	bne	a0, a1, .+0x0ffe+2
+	bne	a0, a1, .-0x1000-2
+	blt	a0, a1, .+0x0ffe+2
+	blt	a0, a1, .-0x1000-2
+	bge	a0, a1, .+0x0ffe+2
+	bge	a0, a1, .-0x1000-2
+	bltu	a0, a1, .+0x0ffe+2
+	bltu	a0, a1, .-0x1000-2
+	bgeu	a0, a1, .+0x0ffe+2
+	bgeu	a0, a1, .-0x1000-2
+	bgt	a0, a1, .+0x0ffe+2
+	bgt	a0, a1, .-0x1000-2
+	ble	a0, a1, .+0x0ffe+2
+	ble	a0, a1, .-0x1000-2
+	bgtu	a0, a1, .+0x0ffe+2
+	bgtu	a0, a1, .-0x1000-2
+	bleu	a0, a1, .+0x0ffe+2
+	bleu	a0, a1, .-0x1000-2
+	beqz	a0, .+0x0ffe+2
+	beqz	a0, .-0x1000-2
+	bnez	a0, .+0x0ffe+2
+	bnez	a0, .-0x1000-2
+	bltz	a0, .+0x0ffe+2
+	bltz	a0, .-0x1000-2
+	bgtz	a0, .+0x0ffe+2
+	bgtz	a0, .-0x1000-2
+	blez	a0, .+0x0ffe+2
+	blez	a0, .-0x1000-2
+	bgez	a0, .+0x0ffe+2
+	bgez	a0, .-0x1000-2
+
+	# Offsets that single instruction cannot represent.
+	# Fail on the exact mode, either fallback or linker error on the non-exact mode.
+	c.beqz	a0, .+0x0fe+2
+	c.beqz	a0, .-0x100-2
+	c.bnez	a0, .+0x0fe+2
+	c.bnez	a0, .-0x100-2
+	jal	a0, .+0x0ffffe+2	# results in a linker error on the non-exact mode
+	jal	a0, .-0x100000-2	# results in a linker error on the non-exact mode
+	c.j	.+0x7fe+2
+	c.j	.-0x800-2
+	c.jal	.+0x7fe+2	# RV32C only
+	c.jal	.-0x800-2	# RV32C only
+.endif
diff --git a/gas/testsuite/gas/riscv/exact.d b/gas/testsuite/gas/riscv/exact.d
new file mode 100644
index 000000000000..3af23035800e
--- /dev/null
+++ b/gas/testsuite/gas/riscv/exact.d
@@ -0,0 +1,15 @@
+#as: -march=rv32ic
+#objdump: -d -Mno-aliases
+
+.*:     file format .*
+
+
+Disassembly of section \.text:
+
+0+ <\.text>:
+[ 	]+0:[ 	]+4108[ 	]+c\.lw[ 	]+a0,0\(a0\)
+[ 	]+2:[ 	]+4108[ 	]+c\.lw[ 	]+a0,0\(a0\)
+[ 	]+4:[ 	]+00052503[ 	]+lw[ 	]+a0,0\(a0\)
+[ 	]+8:[ 	]+4108[ 	]+c\.lw[ 	]+a0,0\(a0\)
+[ 	]+a:[ 	]+4108[ 	]+c\.lw[ 	]+a0,0\(a0\)
+[ 	]+c:[ 	]+4108[ 	]+c\.lw[ 	]+a0,0\(a0\)
diff --git a/gas/testsuite/gas/riscv/exact.s b/gas/testsuite/gas/riscv/exact.s
new file mode 100644
index 000000000000..89f828ebdb1f
--- /dev/null
+++ b/gas/testsuite/gas/riscv/exact.s
@@ -0,0 +1,11 @@
+	# noexact by default.
+	lw	a0, 0(a0)
+	c.lw	a0, 0(a0)
+
+	.option	exact
+	lw	a0, 0(a0)
+	c.lw	a0, 0(a0)
+
+	.option	noexact
+	lw	a0, 0(a0)
+	c.lw	a0, 0(a0)
diff --git a/gas/testsuite/gas/riscv/no-relax-branch-offset-fail.l b/gas/testsuite/gas/riscv/no-relax-branch-offset-fail.l
index 66eedd6e2fef..65761dc4d365 100644
--- a/gas/testsuite/gas/riscv/no-relax-branch-offset-fail.l
+++ b/gas/testsuite/gas/riscv/no-relax-branch-offset-fail.l
@@ -5,4 +5,7 @@
 .*:10: Error: offset \(-1048578\) is invalid for J-type immediate
 .*:14: Error: offset \(\+1048576\) is invalid for J-type immediate
 .*:17: Error: offset \(-1048578\) is invalid for J-type immediate
-.*:20: Error: offset \(\+1\) is invalid for CJ-type immediate
+.*:20: Error: offset \(\+7\) is invalid for J-type immediate
+.*:21: Error: offset \(\+5\) is invalid for B-type immediate
+.*:22: Error: offset \(\+3\) is invalid for CJ-type immediate
+.*:23: Error: offset \(\+1\) is invalid for CB-type immediate
diff --git a/gas/testsuite/gas/riscv/no-relax-branch-offset-fail.s b/gas/testsuite/gas/riscv/no-relax-branch-offset-fail.s
index 98a0978e7fc3..4e8ac3bd78ad 100644
--- a/gas/testsuite/gas/riscv/no-relax-branch-offset-fail.s
+++ b/gas/testsuite/gas/riscv/no-relax-branch-offset-fail.s
@@ -1,10 +1,10 @@
-	.option	norelax
+	.option exact
 
 	# Relative to the current instruction.
 	j	.+0x0ffffe+2
 	j	.-0x100000-2
 
-	# Relative to local labels (make sure that all instructions except "c.j" occupy 4-bytes).
+	# Relative to local labels (all instructions except "c.*" occupy 4-bytes).
 	j	1f+0x0ffffe-4+2
 1:
 	j	2f-0x100000-4-2
@@ -16,5 +16,8 @@
 	lui	t0, 0x2abcd
 	j	4b-0x100000+4-2
 
-	# Jump to odd address (violates instruction alignment).
-	c.j	.+1
+	# Jump or branch to odd address (violates instruction alignment).
+	j	.+7
+	bnez	a0, .+5
+	c.j	.+3
+	c.bnez	a0, .+1
diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h
index c5dd546aac56..c78289c150d5 100644
--- a/include/opcode/riscv.h
+++ b/include/opcode/riscv.h
@@ -673,6 +673,12 @@ struct riscv_opcode
 #define INSN_8_BYTE		0x00000040
 #define INSN_16_BYTE		0x00000050
 
+/* Instruction is prohibited in the exact mode.
+
+   In the exact mode, regular aliases (with INSN_ALIAS) are allowed if
+   the instruction is neither compressed (one-by-one) nor relaxed.  */
+#define INSN_NON_EXACT		0x00000080
+
 /* Instruction is actually a macro.  It should be ignored by the
    disassembler, and requires special treatment by the assembler.  */
 #define INSN_MACRO		0xffffffff
diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c
index 340d1255e181..50ff20c1d471 100644
--- a/opcodes/riscv-opc.c
+++ b/opcodes/riscv-opc.c
@@ -423,13 +423,13 @@ const struct riscv_opcode riscv_opcodes[] =
 {"prefetch.i",  0, INSN_CLASS_ZICBOP, "Wif(s)", MATCH_PREFETCH_I, MASK_PREFETCH_I, match_opcode, 0 },
 {"prefetch.r",  0, INSN_CLASS_ZICBOP, "Wif(s)", MATCH_PREFETCH_R, MASK_PREFETCH_R, match_opcode, 0 },
 {"prefetch.w",  0, INSN_CLASS_ZICBOP, "Wif(s)", MATCH_PREFETCH_W, MASK_PREFETCH_W, match_opcode, 0 },
-{"ntl.p1",      0, INSN_CLASS_ZIHINTNTL_AND_C, "", MATCH_C_NTL_P1, MASK_C_NTL_P1, match_opcode, INSN_ALIAS },
+{"ntl.p1",      0, INSN_CLASS_ZIHINTNTL_AND_C, "", MATCH_C_NTL_P1, MASK_C_NTL_P1, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
 {"ntl.p1",      0, INSN_CLASS_ZIHINTNTL,       "", MATCH_NTL_P1, MASK_NTL_P1, match_opcode, 0 },
-{"ntl.pall",    0, INSN_CLASS_ZIHINTNTL_AND_C, "", MATCH_C_NTL_PALL, MASK_C_NTL_PALL, match_opcode, INSN_ALIAS },
+{"ntl.pall",    0, INSN_CLASS_ZIHINTNTL_AND_C, "", MATCH_C_NTL_PALL, MASK_C_NTL_PALL, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
 {"ntl.pall",    0, INSN_CLASS_ZIHINTNTL,       "", MATCH_NTL_PALL, MASK_NTL_PALL, match_opcode, 0 },
-{"ntl.s1",      0, INSN_CLASS_ZIHINTNTL_AND_C, "", MATCH_C_NTL_S1, MASK_C_NTL_S1, match_opcode, INSN_ALIAS },
+{"ntl.s1",      0, INSN_CLASS_ZIHINTNTL_AND_C, "", MATCH_C_NTL_S1, MASK_C_NTL_S1, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
 {"ntl.s1",      0, INSN_CLASS_ZIHINTNTL,       "", MATCH_NTL_S1, MASK_NTL_S1, match_opcode, 0 },
-{"ntl.all",     0, INSN_CLASS_ZIHINTNTL_AND_C, "", MATCH_C_NTL_ALL, MASK_C_NTL_ALL, match_opcode, INSN_ALIAS },
+{"ntl.all",     0, INSN_CLASS_ZIHINTNTL_AND_C, "", MATCH_C_NTL_ALL, MASK_C_NTL_ALL, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
 {"ntl.all",     0, INSN_CLASS_ZIHINTNTL,       "", MATCH_NTL_ALL, MASK_NTL_ALL, match_opcode, 0 },
 {"c.ntl.p1",    0, INSN_CLASS_ZIHINTNTL_AND_C, "", MATCH_C_NTL_P1, MASK_C_NTL_P1, match_opcode, 0 },
 {"c.ntl.pall",  0, INSN_CLASS_ZIHINTNTL_AND_C, "", MATCH_C_NTL_PALL, MASK_C_NTL_PALL, match_opcode, 0 },
@@ -440,17 +440,17 @@ const struct riscv_opcode riscv_opcodes[] =
 /* Basic RVI instructions and aliases.  */
 {"unimp",       0, INSN_CLASS_C, "",          0, 0xffffU, match_opcode, INSN_ALIAS },
 {"unimp",       0, INSN_CLASS_I, "",          MATCH_CSRRW|(CSR_CYCLE << OP_SH_CSR), 0xffffffffU,  match_opcode, 0 }, /* csrw cycle, x0  */
-{"ebreak",      0, INSN_CLASS_C, "",          MATCH_C_EBREAK, MASK_C_EBREAK, match_opcode, INSN_ALIAS },
+{"ebreak",      0, INSN_CLASS_C, "",          MATCH_C_EBREAK, MASK_C_EBREAK, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
 {"ebreak",      0, INSN_CLASS_I, "",          MATCH_EBREAK, MASK_EBREAK, match_opcode, 0 },
-{"sbreak",      0, INSN_CLASS_C, "",          MATCH_C_EBREAK, MASK_C_EBREAK, match_opcode, INSN_ALIAS },
+{"sbreak",      0, INSN_CLASS_C, "",          MATCH_C_EBREAK, MASK_C_EBREAK, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
 {"sbreak",      0, INSN_CLASS_I, "",          MATCH_EBREAK, MASK_EBREAK, match_opcode, INSN_ALIAS },
-{"ret",         0, INSN_CLASS_C, "",          MATCH_C_JR|(X_RA << OP_SH_RD), MASK_C_JR|MASK_RD, match_opcode, INSN_ALIAS|INSN_BRANCH },
+{"ret",         0, INSN_CLASS_C, "",          MATCH_C_JR|(X_RA << OP_SH_RD), MASK_C_JR|MASK_RD, match_opcode, INSN_ALIAS|INSN_BRANCH|INSN_NON_EXACT },
 {"ret",         0, INSN_CLASS_I, "",          MATCH_JALR|(X_RA << OP_SH_RS1), MASK_JALR|MASK_RD|MASK_RS1|MASK_IMM, match_opcode, INSN_ALIAS|INSN_BRANCH },
-{"jr",          0, INSN_CLASS_C, "d",         MATCH_C_JR, MASK_C_JR, match_rd_nonzero, INSN_ALIAS|INSN_BRANCH },
+{"jr",          0, INSN_CLASS_C, "d",         MATCH_C_JR, MASK_C_JR, match_rd_nonzero, INSN_ALIAS|INSN_BRANCH|INSN_NON_EXACT },
 {"jr",          0, INSN_CLASS_I, "s",         MATCH_JALR, MASK_JALR|MASK_RD|MASK_IMM, match_opcode, INSN_ALIAS|INSN_BRANCH },
 {"jr",          0, INSN_CLASS_I, "o(s)",      MATCH_JALR, MASK_JALR|MASK_RD, match_opcode, INSN_ALIAS|INSN_BRANCH },
 {"jr",          0, INSN_CLASS_I, "s,j",       MATCH_JALR, MASK_JALR|MASK_RD, match_opcode, INSN_ALIAS|INSN_BRANCH },
-{"jalr",        0, INSN_CLASS_C, "d",         MATCH_C_JALR, MASK_C_JALR, match_rd_nonzero, INSN_ALIAS|INSN_JSR },
+{"jalr",        0, INSN_CLASS_C, "d",         MATCH_C_JALR, MASK_C_JALR, match_rd_nonzero, INSN_ALIAS|INSN_JSR|INSN_NON_EXACT },
 {"jalr",        0, INSN_CLASS_I, "s",         MATCH_JALR|(X_RA << OP_SH_RD), MASK_JALR|MASK_RD|MASK_IMM, match_opcode, INSN_ALIAS|INSN_JSR },
 {"jalr",        0, INSN_CLASS_I, "o(s)",      MATCH_JALR|(X_RA << OP_SH_RD), MASK_JALR|MASK_RD, match_opcode, INSN_ALIAS|INSN_JSR },
 {"jalr",        0, INSN_CLASS_I, "s,j",       MATCH_JALR|(X_RA << OP_SH_RD), MASK_JALR|MASK_RD, match_opcode, INSN_ALIAS|INSN_JSR },
@@ -458,9 +458,9 @@ const struct riscv_opcode riscv_opcodes[] =
 {"jalr",        0, INSN_CLASS_I, "d,o(s)",    MATCH_JALR, MASK_JALR, match_opcode, INSN_JSR },
 {"jalr",        0, INSN_CLASS_I, "d,s,1",     MATCH_JALR, MASK_JALR|MASK_IMM, match_opcode, INSN_JSR },
 {"jalr",        0, INSN_CLASS_I, "d,s,j",     MATCH_JALR, MASK_JALR, match_opcode, INSN_JSR },
-{"j",           0, INSN_CLASS_C, "Ca",        MATCH_C_J, MASK_C_J, match_opcode, INSN_ALIAS|INSN_BRANCH },
+{"j",           0, INSN_CLASS_C, "Ca",        MATCH_C_J, MASK_C_J, match_opcode, INSN_ALIAS|INSN_BRANCH|INSN_NON_EXACT },
 {"j",           0, INSN_CLASS_I, "a",         MATCH_JAL, MASK_JAL|MASK_RD, match_opcode, INSN_ALIAS|INSN_BRANCH },
-{"jal",        32, INSN_CLASS_C, "Ca",        MATCH_C_JAL, MASK_C_JAL, match_opcode, INSN_ALIAS|INSN_JSR },
+{"jal",        32, INSN_CLASS_C, "Ca",        MATCH_C_JAL, MASK_C_JAL, match_opcode, INSN_ALIAS|INSN_JSR|INSN_NON_EXACT },
 {"jal",         0, INSN_CLASS_I, "a",         MATCH_JAL|(X_RA << OP_SH_RD), MASK_JAL|MASK_RD, match_opcode, INSN_ALIAS|INSN_JSR },
 {"jal",         0, INSN_CLASS_I, "d,a",       MATCH_JAL, MASK_JAL, match_opcode, INSN_JSR },
 {"call",        0, INSN_CLASS_I, "d,c",       (X_T1 << OP_SH_RS1), (int) M_CALL, NULL, INSN_MACRO },
@@ -468,31 +468,31 @@ const struct riscv_opcode riscv_opcodes[] =
 {"tail",        0, INSN_CLASS_ZICFILP, "c",   (X_T2 << OP_SH_RS1), (int) M_CALL, NULL, INSN_MACRO },
 {"tail",        0, INSN_CLASS_I, "c",         (X_T1 << OP_SH_RS1), (int) M_CALL, NULL, INSN_MACRO },
 {"jump",        0, INSN_CLASS_I, "c,s",       0, (int) M_CALL, match_rs1_nonzero, INSN_MACRO },
-{"nop",         0, INSN_CLASS_C, "",          MATCH_C_ADDI, 0xffff, match_opcode, INSN_ALIAS },
+{"nop",         0, INSN_CLASS_C, "",          MATCH_C_ADDI, 0xffff, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
 {"nop",         0, INSN_CLASS_I, "",          MATCH_ADDI, MASK_ADDI|MASK_RD|MASK_RS1|MASK_IMM, match_opcode, INSN_ALIAS },
-{"lui",         0, INSN_CLASS_C, "d,Cu",      MATCH_C_LUI, MASK_C_LUI, match_c_lui, INSN_ALIAS },
+{"lui",         0, INSN_CLASS_C, "d,Cu",      MATCH_C_LUI, MASK_C_LUI, match_c_lui, INSN_ALIAS | INSN_NON_EXACT },
 {"lui",         0, INSN_CLASS_I, "d,u",       MATCH_LUI, MASK_LUI, match_opcode, 0 },
-{"li",          0, INSN_CLASS_C, "d,Cv",      MATCH_C_LUI, MASK_C_LUI, match_c_lui, INSN_ALIAS },
-{"li",          0, INSN_CLASS_C, "d,Co",      MATCH_C_LI, MASK_C_LI, match_rd_nonzero, INSN_ALIAS },
+{"li",          0, INSN_CLASS_C, "d,Cv",      MATCH_C_LUI, MASK_C_LUI, match_c_lui, INSN_ALIAS | INSN_NON_EXACT },
+{"li",          0, INSN_CLASS_C, "d,Co",      MATCH_C_LI, MASK_C_LI, match_rd_nonzero, INSN_ALIAS | INSN_NON_EXACT },
 {"li",          0, INSN_CLASS_I, "d,j",       MATCH_ADDI, MASK_ADDI|MASK_RS1, match_opcode, INSN_ALIAS }, /* addi  */
 {"li",          0, INSN_CLASS_I, "d,I",       0, (int) M_LI,  NULL, INSN_MACRO },
-{"mv",          0, INSN_CLASS_C, "d,CV",      MATCH_C_MV, MASK_C_MV, match_c_add, INSN_ALIAS },
+{"mv",          0, INSN_CLASS_C, "d,CV",      MATCH_C_MV, MASK_C_MV, match_c_add, INSN_ALIAS | INSN_NON_EXACT },
 {"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_C, "d,CV",      MATCH_C_MV, MASK_C_MV, match_c_add, INSN_ALIAS | INSN_NON_EXACT },
 {"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_ZCB, "Cs,Cw",   MATCH_C_ZEXT_B, MASK_C_ZEXT_B, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
 {"zext.b",      0, INSN_CLASS_I, "d,s",       MATCH_ANDI|ENCODE_ITYPE_IMM (255), MASK_ANDI | MASK_IMM, 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_ZCB, "Cs,Cw,Wcf",MATCH_C_ZEXT_B, MASK_C_ZEXT_B, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
+{"andi",        0, INSN_CLASS_C, "Cs,Cw,Co",  MATCH_C_ANDI, MASK_C_ANDI, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
 {"andi",        0, INSN_CLASS_I, "d,s,j",     MATCH_ANDI, MASK_ANDI, match_opcode, 0 },
-{"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_C, "Cs,Cw,Ct",  MATCH_C_AND, MASK_C_AND, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
+{"and",         0, INSN_CLASS_C, "Cs,Ct,Cw",  MATCH_C_AND, MASK_C_AND, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
+{"and",         0, INSN_CLASS_C, "Cs,Cw,Co",  MATCH_C_ANDI, MASK_C_ANDI, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
 {"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 },
-{"beqz",        0, INSN_CLASS_C, "Cs,Cp",     MATCH_C_BEQZ, MASK_C_BEQZ, match_opcode, INSN_ALIAS|INSN_CONDBRANCH },
+{"beqz",        0, INSN_CLASS_C, "Cs,Cp",     MATCH_C_BEQZ, MASK_C_BEQZ, match_opcode, INSN_ALIAS|INSN_CONDBRANCH|INSN_NON_EXACT },
 {"beqz",        0, INSN_CLASS_I, "s,p",       MATCH_BEQ, MASK_BEQ|MASK_RS2, match_opcode, INSN_ALIAS|INSN_CONDBRANCH },
-{"beq",         0, INSN_CLASS_C, "Cs,Cz,Cp",  MATCH_C_BEQZ, MASK_C_BEQZ, match_opcode, INSN_ALIAS|INSN_CONDBRANCH },
+{"beq",         0, INSN_CLASS_C, "Cs,Cz,Cp",  MATCH_C_BEQZ, MASK_C_BEQZ, match_opcode, INSN_ALIAS|INSN_CONDBRANCH|INSN_NON_EXACT },
 {"beq",         0, INSN_CLASS_I, "s,t,p",     MATCH_BEQ, MASK_BEQ, match_opcode, INSN_CONDBRANCH },
 {"blez",        0, INSN_CLASS_I, "t,p",       MATCH_BGE, MASK_BGE|MASK_RS1, match_opcode, INSN_ALIAS|INSN_CONDBRANCH },
 {"bgez",        0, INSN_CLASS_I, "s,p",       MATCH_BGE, MASK_BGE|MASK_RS2, match_opcode, INSN_ALIAS|INSN_CONDBRANCH },
@@ -506,23 +506,23 @@ const struct riscv_opcode riscv_opcodes[] =
 {"bltu",        0, INSN_CLASS_I, "s,t,p",     MATCH_BLTU, MASK_BLTU, match_opcode, INSN_CONDBRANCH },
 {"bgt",         0, INSN_CLASS_I, "t,s,p",     MATCH_BLT, MASK_BLT, match_opcode, INSN_ALIAS|INSN_CONDBRANCH },
 {"bgtu",        0, INSN_CLASS_I, "t,s,p",     MATCH_BLTU, MASK_BLTU, match_opcode, INSN_ALIAS|INSN_CONDBRANCH },
-{"bnez",        0, INSN_CLASS_C, "Cs,Cp",     MATCH_C_BNEZ, MASK_C_BNEZ, match_opcode, INSN_ALIAS|INSN_CONDBRANCH },
+{"bnez",        0, INSN_CLASS_C, "Cs,Cp",     MATCH_C_BNEZ, MASK_C_BNEZ, match_opcode, INSN_ALIAS|INSN_CONDBRANCH|INSN_NON_EXACT },
 {"bnez",        0, INSN_CLASS_I, "s,p",       MATCH_BNE, MASK_BNE|MASK_RS2, match_opcode, INSN_ALIAS|INSN_CONDBRANCH },
-{"bne",         0, INSN_CLASS_C, "Cs,Cz,Cp",  MATCH_C_BNEZ, MASK_C_BNEZ, match_opcode, INSN_ALIAS|INSN_CONDBRANCH },
+{"bne",         0, INSN_CLASS_C, "Cs,Cz,Cp",  MATCH_C_BNEZ, MASK_C_BNEZ, match_opcode, INSN_ALIAS|INSN_CONDBRANCH|INSN_NON_EXACT },
 {"bne",         0, INSN_CLASS_I, "s,t,p",     MATCH_BNE, MASK_BNE, match_opcode, INSN_CONDBRANCH },
-{"addi",        0, INSN_CLASS_C, "Ct,Cc,CK",  MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN, match_c_addi4spn, INSN_ALIAS },
-{"addi",        0, INSN_CLASS_C, "d,CU,Cj",   MATCH_C_ADDI, MASK_C_ADDI, match_rd_nonzero, INSN_ALIAS },
-{"addi",        0, INSN_CLASS_C, "d,CU,z",    MATCH_C_NOP, MASK_C_ADDI|MASK_RVC_IMM, match_c_nop, INSN_ALIAS },
-{"addi",        0, INSN_CLASS_C, "Cc,Cc,CL",  MATCH_C_ADDI16SP, MASK_C_ADDI16SP, match_c_addi16sp, INSN_ALIAS },
-{"addi",        0, INSN_CLASS_C, "d,Cz,Co",   MATCH_C_LI, MASK_C_LI, match_rd_nonzero, INSN_ALIAS },
-{"addi",        0, INSN_CLASS_C, "d,CV,z",    MATCH_C_MV, MASK_C_MV, match_c_add, INSN_ALIAS },
+{"addi",        0, INSN_CLASS_C, "Ct,Cc,CK",  MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN, match_c_addi4spn, INSN_ALIAS | INSN_NON_EXACT },
+{"addi",        0, INSN_CLASS_C, "d,CU,Cj",   MATCH_C_ADDI, MASK_C_ADDI, match_rd_nonzero, INSN_ALIAS | INSN_NON_EXACT },
+{"addi",        0, INSN_CLASS_C, "d,CU,z",    MATCH_C_NOP, MASK_C_ADDI|MASK_RVC_IMM, match_c_nop, INSN_ALIAS | INSN_NON_EXACT },
+{"addi",        0, INSN_CLASS_C, "Cc,Cc,CL",  MATCH_C_ADDI16SP, MASK_C_ADDI16SP, match_c_addi16sp, INSN_ALIAS | INSN_NON_EXACT },
+{"addi",        0, INSN_CLASS_C, "d,Cz,Co",   MATCH_C_LI, MASK_C_LI, match_rd_nonzero, INSN_ALIAS | INSN_NON_EXACT },
+{"addi",        0, INSN_CLASS_C, "d,CV,z",    MATCH_C_MV, MASK_C_MV, match_c_add, INSN_ALIAS | INSN_NON_EXACT },
 {"addi",        0, INSN_CLASS_I, "d,s,j",     MATCH_ADDI, MASK_ADDI, match_opcode, 0 },
-{"add",         0, INSN_CLASS_C, "d,CU,CV",   MATCH_C_ADD, MASK_C_ADD, match_c_add, INSN_ALIAS },
-{"add",         0, INSN_CLASS_C, "d,CV,CU",   MATCH_C_ADD, MASK_C_ADD, match_c_add, INSN_ALIAS },
-{"add",         0, INSN_CLASS_C, "d,CU,Co",   MATCH_C_ADDI, MASK_C_ADDI, match_rd_nonzero, INSN_ALIAS },
-{"add",         0, INSN_CLASS_C, "Ct,Cc,CK",  MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN, match_c_addi4spn, INSN_ALIAS },
-{"add",         0, INSN_CLASS_C, "Cc,Cc,CL",  MATCH_C_ADDI16SP, MASK_C_ADDI16SP, match_c_addi16sp, INSN_ALIAS },
-{"add",         0, INSN_CLASS_C, "d,Cz,CV",   MATCH_C_MV, MASK_C_MV, match_c_add, INSN_ALIAS },
+{"add",         0, INSN_CLASS_C, "d,CU,CV",   MATCH_C_ADD, MASK_C_ADD, match_c_add, INSN_ALIAS | INSN_NON_EXACT },
+{"add",         0, INSN_CLASS_C, "d,CV,CU",   MATCH_C_ADD, MASK_C_ADD, match_c_add, INSN_ALIAS | INSN_NON_EXACT },
+{"add",         0, INSN_CLASS_C, "d,CU,Co",   MATCH_C_ADDI, MASK_C_ADDI, match_rd_nonzero, INSN_ALIAS | INSN_NON_EXACT },
+{"add",         0, INSN_CLASS_C, "Ct,Cc,CK",  MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN, match_c_addi4spn, INSN_ALIAS | INSN_NON_EXACT },
+{"add",         0, INSN_CLASS_C, "Cc,Cc,CL",  MATCH_C_ADDI16SP, MASK_C_ADDI16SP, match_c_addi16sp, INSN_ALIAS | INSN_NON_EXACT },
+{"add",         0, INSN_CLASS_C, "d,Cz,CV",   MATCH_C_MV, MASK_C_MV, match_c_add, INSN_ALIAS | INSN_NON_EXACT },
 {"add",         0, INSN_CLASS_I, "d,s,t",     MATCH_ADD, MASK_ADD, match_opcode, 0 },
 {"add",         0, INSN_CLASS_I, "d,s,t,1",   MATCH_ADD, MASK_ADD, match_opcode, 0 },
 {"add",         0, INSN_CLASS_I, "d,s,j",     MATCH_ADDI, MASK_ADDI, match_opcode, INSN_ALIAS },
@@ -536,44 +536,44 @@ const struct riscv_opcode riscv_opcodes[] =
 {"mips.ehb", 0, INSN_CLASS_XMIPSEXECTL, "", MATCH_MIPS_EHB, MASK_MIPS_EHB, match_opcode, 0 },
 {"mips.ihb", 0, INSN_CLASS_XMIPSEXECTL, "", MATCH_MIPS_IHB, MASK_MIPS_IHB, match_opcode, 0 },
 {"mips.pause", 0, INSN_CLASS_XMIPSEXECTL, "", MATCH_MIPS_PAUSE, MASK_MIPS_PAUSE, match_opcode, 0 },
-{"slli",        0, INSN_CLASS_C, "d,CU,C>",   MATCH_C_SLLI, MASK_C_SLLI, match_slli_as_c_slli, INSN_ALIAS },
+{"slli",        0, INSN_CLASS_C, "d,CU,C>",   MATCH_C_SLLI, MASK_C_SLLI, match_slli_as_c_slli, INSN_ALIAS | INSN_NON_EXACT },
 {"slli",        0, INSN_CLASS_I, "d,s,>",     MATCH_SLLI, MASK_SLLI, match_opcode, 0 },
-{"sll",         0, INSN_CLASS_C, "d,CU,C>",   MATCH_C_SLLI, MASK_C_SLLI, match_slli_as_c_slli, INSN_ALIAS },
+{"sll",         0, INSN_CLASS_C, "d,CU,C>",   MATCH_C_SLLI, MASK_C_SLLI, match_slli_as_c_slli, INSN_ALIAS | INSN_NON_EXACT },
 {"sll",         0, INSN_CLASS_I, "d,s,t",     MATCH_SLL, MASK_SLL, match_opcode, 0 },
 {"sll",         0, INSN_CLASS_I, "d,s,>",     MATCH_SLLI, MASK_SLLI, match_opcode, INSN_ALIAS },
-{"srli",        0, INSN_CLASS_C, "Cs,Cw,C>",  MATCH_C_SRLI, MASK_C_SRLI, match_srxi_as_c_srxi, INSN_ALIAS },
+{"srli",        0, INSN_CLASS_C, "Cs,Cw,C>",  MATCH_C_SRLI, MASK_C_SRLI, match_srxi_as_c_srxi, INSN_ALIAS | INSN_NON_EXACT },
 {"srli",        0, INSN_CLASS_I, "d,s,>",     MATCH_SRLI, MASK_SRLI, match_opcode, 0 },
-{"srl",         0, INSN_CLASS_C, "Cs,Cw,C>",  MATCH_C_SRLI, MASK_C_SRLI, match_srxi_as_c_srxi, INSN_ALIAS },
+{"srl",         0, INSN_CLASS_C, "Cs,Cw,C>",  MATCH_C_SRLI, MASK_C_SRLI, match_srxi_as_c_srxi, INSN_ALIAS | INSN_NON_EXACT },
 {"srl",         0, INSN_CLASS_I, "d,s,t",     MATCH_SRL, MASK_SRL, match_opcode, 0 },
 {"srl",         0, INSN_CLASS_I, "d,s,>",     MATCH_SRLI, MASK_SRLI, match_opcode, INSN_ALIAS },
-{"srai",        0, INSN_CLASS_C, "Cs,Cw,C>",  MATCH_C_SRAI, MASK_C_SRAI, match_srxi_as_c_srxi, INSN_ALIAS },
+{"srai",        0, INSN_CLASS_C, "Cs,Cw,C>",  MATCH_C_SRAI, MASK_C_SRAI, match_srxi_as_c_srxi, INSN_ALIAS | INSN_NON_EXACT },
 {"srai",        0, INSN_CLASS_I, "d,s,>",     MATCH_SRAI, MASK_SRAI, match_opcode, 0 },
-{"sra",         0, INSN_CLASS_C, "Cs,Cw,C>",  MATCH_C_SRAI, MASK_C_SRAI, match_srxi_as_c_srxi, INSN_ALIAS },
+{"sra",         0, INSN_CLASS_C, "Cs,Cw,C>",  MATCH_C_SRAI, MASK_C_SRAI, match_srxi_as_c_srxi, INSN_ALIAS | INSN_NON_EXACT },
 {"sra",         0, INSN_CLASS_I, "d,s,t",     MATCH_SRA, MASK_SRA, match_opcode, 0 },
 {"sra",         0, INSN_CLASS_I, "d,s,>",     MATCH_SRAI, MASK_SRAI, match_opcode, INSN_ALIAS },
-{"sub",         0, INSN_CLASS_C, "Cs,Cw,Ct",  MATCH_C_SUB, MASK_C_SUB, match_opcode, INSN_ALIAS },
+{"sub",         0, INSN_CLASS_C, "Cs,Cw,Ct",  MATCH_C_SUB, MASK_C_SUB, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
 {"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_Lx, match_rd_nonzero, 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_ZCB, "Ct,Wcb(Cs)", MATCH_C_LBU, MASK_C_LBU, match_opcode, INSN_ALIAS|INSN_DREF|INSN_1_BYTE|INSN_NON_EXACT },
 {"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_Lx, match_rd_nonzero, 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_ZCB, "Ct,Wch(Cs)", MATCH_C_LH, MASK_C_LH, match_opcode, INSN_ALIAS|INSN_DREF|INSN_2_BYTE|INSN_NON_EXACT },
 {"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_Lx, match_rd_nonzero, 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_ZCB, "Ct,Wch(Cs)", MATCH_C_LHU, MASK_C_LHU, match_opcode, INSN_ALIAS|INSN_DREF|INSN_2_BYTE|INSN_NON_EXACT },
 {"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_Lx, match_rd_nonzero, 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_C, "d,Cm(Cc)",  MATCH_C_LWSP, MASK_C_LWSP, match_rd_nonzero, INSN_ALIAS|INSN_DREF|INSN_4_BYTE|INSN_NON_EXACT },
+{"lw",          0, INSN_CLASS_C, "Ct,Ck(Cs)", MATCH_C_LW, MASK_C_LW, match_opcode, INSN_ALIAS|INSN_DREF|INSN_4_BYTE|INSN_NON_EXACT },
 {"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_Lx, match_rd_nonzero, INSN_MACRO },
-{"not",         0, INSN_CLASS_ZCB,  "Cs,Cw",  MATCH_C_NOT, MASK_C_NOT, match_opcode, INSN_ALIAS },
+{"not",         0, INSN_CLASS_ZCB,  "Cs,Cw",  MATCH_C_NOT, MASK_C_NOT, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
 {"not",         0, INSN_CLASS_I, "d,s",       MATCH_XORI|MASK_IMM, MASK_XORI|MASK_IMM, match_opcode, INSN_ALIAS },
 {"ori",         0, INSN_CLASS_I, "d,s,j",     MATCH_ORI, MASK_ORI, match_opcode, 0 },
 {"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 },
-{"or",          0, INSN_CLASS_C, "Cs,Ct,Cw",  MATCH_C_OR, MASK_C_OR, match_opcode, INSN_ALIAS },
+{"or",          0, INSN_CLASS_C, "Cs,Cw,Ct",  MATCH_C_OR, MASK_C_OR, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
+{"or",          0, INSN_CLASS_C, "Cs,Ct,Cw",  MATCH_C_OR, MASK_C_OR, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
 {"or",          0, INSN_CLASS_I, "d,s,t",     MATCH_OR, MASK_OR, match_opcode, 0 },
 
 /* Zicfilp instructions.  */
@@ -592,14 +592,14 @@ 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_ZCB, "Ct,Wcb(Cs)", MATCH_C_SB, MASK_C_SB, match_opcode, INSN_DREF|INSN_1_BYTE|INSN_ALIAS|INSN_NON_EXACT },
 {"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_Sx_FSx, match_rs1_nonzero, 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_ZCB, "Ct,Wch(Cs)", MATCH_C_SH, MASK_C_SH, match_opcode, INSN_DREF|INSN_2_BYTE|INSN_ALIAS|INSN_NON_EXACT },
 {"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_Sx_FSx, match_rs1_nonzero, 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 },
-{"sw",          0, INSN_CLASS_C, "Ct,Ck(Cs)", MATCH_C_SW, MASK_C_SW, match_opcode, INSN_ALIAS|INSN_DREF|INSN_4_BYTE },
+{"sw",          0, INSN_CLASS_C, "CV,CM(Cc)", MATCH_C_SWSP, MASK_C_SWSP, match_opcode, INSN_ALIAS|INSN_DREF|INSN_4_BYTE|INSN_NON_EXACT },
+{"sw",          0, INSN_CLASS_C, "Ct,Ck(Cs)", MATCH_C_SW, MASK_C_SW, match_opcode, INSN_ALIAS|INSN_DREF|INSN_4_BYTE|INSN_NON_EXACT },
 {"sw",          0, INSN_CLASS_I, "t,q(s)",    MATCH_SW, MASK_SW, match_opcode, INSN_DREF|INSN_4_BYTE },
 {"sw",          0, INSN_CLASS_I, "t,A,s",     0, (int) M_Sx_FSx, match_rs1_nonzero, INSN_MACRO },
 {"fence",       0, INSN_CLASS_I, "",          MATCH_FENCE|MASK_PRED|MASK_SUCC, MASK_FENCE|MASK_RD|MASK_RS1|MASK_IMM, match_opcode, INSN_ALIAS },
@@ -616,26 +616,26 @@ const struct riscv_opcode riscv_opcodes[] =
 {"scall",       0, INSN_CLASS_I, "",          MATCH_SCALL, MASK_SCALL, match_opcode, 0 },
 {"xori",        0, INSN_CLASS_I, "d,s,j",     MATCH_XORI, MASK_XORI, match_opcode, 0 },
 {"xor",         0, INSN_CLASS_I, "d,s,j",     MATCH_XORI, MASK_XORI, match_opcode, INSN_ALIAS },
-{"xor",         0, INSN_CLASS_C, "Cs,Cw,Ct",  MATCH_C_XOR, MASK_C_XOR, match_opcode, INSN_ALIAS },
-{"xor",         0, INSN_CLASS_C, "Cs,Ct,Cw",  MATCH_C_XOR, MASK_C_XOR, match_opcode, INSN_ALIAS },
+{"xor",         0, INSN_CLASS_C, "Cs,Cw,Ct",  MATCH_C_XOR, MASK_C_XOR, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
+{"xor",         0, INSN_CLASS_C, "Cs,Ct,Cw",  MATCH_C_XOR, MASK_C_XOR, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
 {"xor",         0, INSN_CLASS_I, "d,s,t",     MATCH_XOR, MASK_XOR, match_opcode, 0 },
 {"lwu",        64, INSN_CLASS_I, "d,o(s)",    MATCH_LWU, MASK_LWU, match_opcode, INSN_DREF|INSN_4_BYTE },
 {"lwu",        64, INSN_CLASS_I, "d,A",       0, (int) M_Lx, match_rd_nonzero, INSN_MACRO },
-{"ld",         64, INSN_CLASS_C, "d,Cn(Cc)",  MATCH_C_LDSP, MASK_C_LDSP, match_rd_nonzero, INSN_ALIAS|INSN_DREF|INSN_8_BYTE },
-{"ld",         64, INSN_CLASS_C, "Ct,Cl(Cs)", MATCH_C_LD, MASK_C_LD, match_opcode, INSN_ALIAS|INSN_DREF|INSN_8_BYTE },
+{"ld",         64, INSN_CLASS_C, "d,Cn(Cc)",  MATCH_C_LDSP, MASK_C_LDSP, match_rd_nonzero, INSN_ALIAS|INSN_DREF|INSN_8_BYTE|INSN_NON_EXACT },
+{"ld",         64, INSN_CLASS_C, "Ct,Cl(Cs)", MATCH_C_LD, MASK_C_LD, match_opcode, INSN_ALIAS|INSN_DREF|INSN_8_BYTE|INSN_NON_EXACT },
 {"ld",         64, INSN_CLASS_I, "d,o(s)",    MATCH_LD, MASK_LD, match_opcode, INSN_DREF|INSN_8_BYTE },
 {"ld",         64, INSN_CLASS_I, "d,A",       0, (int) M_Lx, match_rd_nonzero, INSN_MACRO },
-{"sd",         64, INSN_CLASS_C, "CV,CN(Cc)", MATCH_C_SDSP, MASK_C_SDSP, match_opcode, INSN_ALIAS|INSN_DREF|INSN_8_BYTE },
-{"sd",         64, INSN_CLASS_C, "Ct,Cl(Cs)", MATCH_C_SD, MASK_C_SD, match_opcode, INSN_ALIAS|INSN_DREF|INSN_8_BYTE },
+{"sd",         64, INSN_CLASS_C, "CV,CN(Cc)", MATCH_C_SDSP, MASK_C_SDSP, match_opcode, INSN_ALIAS|INSN_DREF|INSN_8_BYTE|INSN_NON_EXACT },
+{"sd",         64, INSN_CLASS_C, "Ct,Cl(Cs)", MATCH_C_SD, MASK_C_SD, match_opcode, INSN_ALIAS|INSN_DREF|INSN_8_BYTE|INSN_NON_EXACT },
 {"sd",         64, INSN_CLASS_I, "t,q(s)",    MATCH_SD, MASK_SD, match_opcode, INSN_DREF|INSN_8_BYTE },
 {"sd",         64, INSN_CLASS_I, "t,A,s",     0, (int) M_Sx_FSx, match_rs1_nonzero, INSN_MACRO },
-{"sext.w",     64, INSN_CLASS_C, "d,CU",      MATCH_C_ADDIW, MASK_C_ADDIW|MASK_RVC_IMM, match_rd_nonzero, INSN_ALIAS },
+{"sext.w",     64, INSN_CLASS_C, "d,CU",      MATCH_C_ADDIW, MASK_C_ADDIW|MASK_RVC_IMM, match_rd_nonzero, INSN_ALIAS | INSN_NON_EXACT },
 {"sext.w",     64, INSN_CLASS_I, "d,s",       MATCH_ADDIW, MASK_ADDIW|MASK_IMM, match_opcode, INSN_ALIAS },
-{"addiw",      64, INSN_CLASS_C, "d,CU,Co",   MATCH_C_ADDIW, MASK_C_ADDIW, match_rd_nonzero, INSN_ALIAS },
+{"addiw",      64, INSN_CLASS_C, "d,CU,Co",   MATCH_C_ADDIW, MASK_C_ADDIW, match_rd_nonzero, INSN_ALIAS | INSN_NON_EXACT },
 {"addiw",      64, INSN_CLASS_I, "d,s,j",     MATCH_ADDIW, MASK_ADDIW, match_opcode, 0 },
-{"addw",       64, INSN_CLASS_C, "Cs,Cw,Ct",  MATCH_C_ADDW, MASK_C_ADDW, match_opcode, INSN_ALIAS },
-{"addw",       64, INSN_CLASS_C, "Cs,Ct,Cw",  MATCH_C_ADDW, MASK_C_ADDW, match_opcode, INSN_ALIAS },
-{"addw",       64, INSN_CLASS_C, "d,CU,Co",   MATCH_C_ADDIW, MASK_C_ADDIW, match_rd_nonzero, INSN_ALIAS },
+{"addw",       64, INSN_CLASS_C, "Cs,Cw,Ct",  MATCH_C_ADDW, MASK_C_ADDW, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
+{"addw",       64, INSN_CLASS_C, "Cs,Ct,Cw",  MATCH_C_ADDW, MASK_C_ADDW, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
+{"addw",       64, INSN_CLASS_C, "d,CU,Co",   MATCH_C_ADDIW, MASK_C_ADDIW, match_rd_nonzero, INSN_ALIAS | INSN_NON_EXACT },
 {"addw",       64, INSN_CLASS_I, "d,s,t",     MATCH_ADDW, MASK_ADDW, match_opcode, 0 },
 {"addw",       64, INSN_CLASS_I, "d,s,j",     MATCH_ADDIW, MASK_ADDIW, match_opcode, INSN_ALIAS },
 {"negw",       64, INSN_CLASS_I, "d,t",       MATCH_SUBW, MASK_SUBW|MASK_RS1, match_opcode, INSN_ALIAS }, /* sub 0  */
@@ -648,7 +648,7 @@ const struct riscv_opcode riscv_opcodes[] =
 {"sraiw",      64, INSN_CLASS_I, "d,s,<",     MATCH_SRAIW, MASK_SRAIW, match_opcode, 0 },
 {"sraw",       64, INSN_CLASS_I, "d,s,t",     MATCH_SRAW, MASK_SRAW, match_opcode, 0 },
 {"sraw",       64, INSN_CLASS_I, "d,s,<",     MATCH_SRAIW, MASK_SRAIW, match_opcode, INSN_ALIAS },
-{"subw",       64, INSN_CLASS_C, "Cs,Cw,Ct",  MATCH_C_SUBW, MASK_C_SUBW, match_opcode, INSN_ALIAS },
+{"subw",       64, INSN_CLASS_C, "Cs,Cw,Ct",  MATCH_C_SUBW, MASK_C_SUBW, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
 {"subw",       64, INSN_CLASS_I, "d,s,t",     MATCH_SUBW, MASK_SUBW, match_opcode, 0 },
 
 /* Atomic memory operation instruction subset.  */
@@ -842,7 +842,7 @@ const struct riscv_opcode riscv_opcodes[] =
 {"amocas.q.aqrl",   64, INSN_CLASS_ZACAS, "d,t,0(s)", MATCH_AMOCAS_Q|MASK_AQRL, MASK_AMOCAS_Q|MASK_AQRL, match_rs2_rd_even, INSN_DREF|INSN_16_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_ZCB_AND_ZMMUL, "Cs,Cw,Ct",  MATCH_C_MUL, MASK_C_MUL, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
 {"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 },
@@ -944,12 +944,12 @@ const struct riscv_opcode riscv_opcodes[] =
 {"fsflags",    0, INSN_CLASS_F_INX,   "d,s",       MATCH_FSFLAGS, MASK_FSFLAGS, match_opcode, INSN_ALIAS },
 {"fsflagsi",   0, INSN_CLASS_F_INX,   "d,Z",       MATCH_FSFLAGSI, MASK_FSFLAGSI, match_opcode, INSN_ALIAS },
 {"fsflagsi",   0, INSN_CLASS_F_INX,   "Z",         MATCH_FSFLAGSI, MASK_FSFLAGSI|MASK_RD, match_opcode, INSN_ALIAS },
-{"flw",       32, INSN_CLASS_F_AND_C, "D,Cm(Cc)",  MATCH_C_FLWSP, MASK_C_FLWSP, match_opcode, INSN_ALIAS|INSN_DREF|INSN_4_BYTE },
-{"flw",       32, INSN_CLASS_F_AND_C, "CD,Ck(Cs)", MATCH_C_FLW, MASK_C_FLW, match_opcode, INSN_ALIAS|INSN_DREF|INSN_4_BYTE },
+{"flw",       32, INSN_CLASS_F_AND_C, "D,Cm(Cc)",  MATCH_C_FLWSP, MASK_C_FLWSP, match_opcode, INSN_ALIAS|INSN_DREF|INSN_4_BYTE|INSN_NON_EXACT },
+{"flw",       32, INSN_CLASS_F_AND_C, "CD,Ck(Cs)", MATCH_C_FLW, MASK_C_FLW, match_opcode, INSN_ALIAS|INSN_DREF|INSN_4_BYTE|INSN_NON_EXACT },
 {"flw",        0, INSN_CLASS_F,   "D,o(s)",    MATCH_FLW, MASK_FLW, match_opcode, INSN_DREF|INSN_4_BYTE },
 {"flw",        0, INSN_CLASS_F,   "D,A,s",     0, (int) M_FLx, match_rs1_nonzero, INSN_MACRO },
-{"fsw",       32, INSN_CLASS_F_AND_C, "CT,CM(Cc)", MATCH_C_FSWSP, MASK_C_FSWSP, match_opcode, INSN_ALIAS|INSN_DREF|INSN_4_BYTE },
-{"fsw",       32, INSN_CLASS_F_AND_C, "CD,Ck(Cs)", MATCH_C_FSW, MASK_C_FSW, match_opcode, INSN_ALIAS|INSN_DREF|INSN_4_BYTE },
+{"fsw",       32, INSN_CLASS_F_AND_C, "CT,CM(Cc)", MATCH_C_FSWSP, MASK_C_FSWSP, match_opcode, INSN_ALIAS|INSN_DREF|INSN_4_BYTE|INSN_NON_EXACT },
+{"fsw",       32, INSN_CLASS_F_AND_C, "CD,Ck(Cs)", MATCH_C_FSW, MASK_C_FSW, match_opcode, INSN_ALIAS|INSN_DREF|INSN_4_BYTE|INSN_NON_EXACT },
 {"fsw",        0, INSN_CLASS_F,   "T,q(s)",    MATCH_FSW, MASK_FSW, match_opcode, INSN_DREF|INSN_4_BYTE },
 {"fsw",        0, INSN_CLASS_F,   "T,A,s",     0, (int) M_Sx_FSx, match_rs1_nonzero, INSN_MACRO },
 {"fmv.x.w",    0, INSN_CLASS_F,   "d,S",       MATCH_FMV_X_S, MASK_FMV_X_S, match_opcode, 0 },
@@ -1006,12 +1006,12 @@ const struct riscv_opcode riscv_opcodes[] =
 {"fcvt.s.lu", 64, INSN_CLASS_F_INX,   "D,s,m",     MATCH_FCVT_S_LU, MASK_FCVT_S_LU, match_opcode, 0 },
 
 /* Double-precision floating-point instruction subset.  */
-{"fld",        0, INSN_CLASS_D_AND_C, "D,Cn(Cc)",  MATCH_C_FLDSP, MASK_C_FLDSP, match_opcode, INSN_ALIAS|INSN_DREF|INSN_8_BYTE },
-{"fld",        0, INSN_CLASS_D_AND_C, "CD,Cl(Cs)", MATCH_C_FLD, MASK_C_FLD, match_opcode, INSN_ALIAS|INSN_DREF|INSN_8_BYTE },
+{"fld",        0, INSN_CLASS_D_AND_C, "D,Cn(Cc)",  MATCH_C_FLDSP, MASK_C_FLDSP, match_opcode, INSN_ALIAS|INSN_DREF|INSN_8_BYTE|INSN_NON_EXACT },
+{"fld",        0, INSN_CLASS_D_AND_C, "CD,Cl(Cs)", MATCH_C_FLD, MASK_C_FLD, match_opcode, INSN_ALIAS|INSN_DREF|INSN_8_BYTE|INSN_NON_EXACT },
 {"fld",        0, INSN_CLASS_D,   "D,o(s)",    MATCH_FLD, MASK_FLD, match_opcode, INSN_DREF|INSN_8_BYTE },
 {"fld",        0, INSN_CLASS_D,   "D,A,s",     0, (int) M_FLx, match_rs1_nonzero, INSN_MACRO },
-{"fsd",        0, INSN_CLASS_D_AND_C, "CT,CN(Cc)", MATCH_C_FSDSP, MASK_C_FSDSP, match_opcode, INSN_ALIAS|INSN_DREF|INSN_8_BYTE },
-{"fsd",        0, INSN_CLASS_D_AND_C, "CD,Cl(Cs)", MATCH_C_FSD, MASK_C_FSD, match_opcode, INSN_ALIAS|INSN_DREF|INSN_8_BYTE },
+{"fsd",        0, INSN_CLASS_D_AND_C, "CT,CN(Cc)", MATCH_C_FSDSP, MASK_C_FSDSP, match_opcode, INSN_ALIAS|INSN_DREF|INSN_8_BYTE|INSN_NON_EXACT },
+{"fsd",        0, INSN_CLASS_D_AND_C, "CD,Cl(Cs)", MATCH_C_FSD, MASK_C_FSD, match_opcode, INSN_ALIAS|INSN_DREF|INSN_8_BYTE|INSN_NON_EXACT },
 {"fsd",        0, INSN_CLASS_D,   "T,q(s)",    MATCH_FSD, MASK_FSD, match_opcode, INSN_DREF|INSN_8_BYTE },
 {"fsd",        0, INSN_CLASS_D,   "T,A,s",     0, (int) M_Sx_FSx, match_rs1_nonzero, INSN_MACRO },
 {"fmv.d",      0, INSN_CLASS_D_INX,   "D,U",       MATCH_FSGNJ_D, MASK_FSGNJ_D, match_rs1_eq_rs2, INSN_ALIAS },
@@ -1184,9 +1184,9 @@ const struct riscv_opcode riscv_opcodes[] =
 {"czero.nez",  0, INSN_CLASS_ZICOND, "d,s,t", MATCH_CZERO_NEZ, MASK_CZERO_NEZ, match_opcode, 0 },
 
 /* Zicfiss instructions.  */
-{"sspush",            0, INSN_CLASS_ZICFISS_AND_ZCMOP, "d", MATCH_C_SSPUSH, MASK_C_SSPUSH, match_rd_x1x5_opcode, INSN_ALIAS },
+{"sspush",            0, INSN_CLASS_ZICFISS_AND_ZCMOP, "d", MATCH_C_SSPUSH, MASK_C_SSPUSH, match_rd_x1x5_opcode, INSN_ALIAS | INSN_NON_EXACT },
 {"sspush",            0, INSN_CLASS_ZICFISS,           "t", MATCH_SSPUSH, MASK_SSPUSH, match_rs2_x1x5_opcode, 0 },
-{"sspopchk",          0, INSN_CLASS_ZICFISS_AND_ZCMOP, "d", MATCH_C_SSPOPCHK, MASK_C_SSPOPCHK, match_rd_x1x5_opcode, INSN_ALIAS },
+{"sspopchk",          0, INSN_CLASS_ZICFISS_AND_ZCMOP, "d", MATCH_C_SSPOPCHK, MASK_C_SSPOPCHK, match_rd_x1x5_opcode, INSN_ALIAS | INSN_NON_EXACT },
 {"sspopchk",          0, INSN_CLASS_ZICFISS,           "s", MATCH_SSPOPCHK, MASK_SSPOPCHK, match_rs1_x1x5_opcode, 0 },
 {"c.sspush",          0, INSN_CLASS_ZICFISS_AND_ZCMOP, "d", MATCH_C_SSPUSH, MASK_C_SSPUSH, match_rd_x1x5_opcode, 0 },
 {"c.sspopchk",        0, INSN_CLASS_ZICFISS_AND_ZCMOP, "d", MATCH_C_SSPOPCHK, MASK_C_SSPOPCHK, match_rd_x1x5_opcode, 0 },
@@ -1297,13 +1297,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_ZCB_AND_ZBB,  "Cs,Cw", MATCH_C_SEXT_B, MASK_C_SEXT_B, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
 {"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, NULL, 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_ZCB_AND_ZBB,  "Cs,Cw", MATCH_C_SEXT_H, MASK_C_SEXT_H, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
 {"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_EXTH, NULL, 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",     0, INSN_CLASS_ZCB_AND_ZBB,  "Cs,Cw", MATCH_C_ZEXT_H, MASK_C_ZEXT_H, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
 {"zext.h",    32, INSN_CLASS_ZBB_OR_ZBKB,  "d,s",   MATCH_PACK, MASK_PACK | MASK_RS2, match_opcode, 0 },
 {"zext.h",    64, INSN_CLASS_ZBB_OR_ZBKB,  "d,s",   MATCH_PACKW, MASK_PACKW | MASK_RS2, match_opcode, 0 },
 {"zext.h",     0, INSN_CLASS_I,         "d,s",   0, (int) M_EXTH, NULL, INSN_MACRO },
@@ -1339,7 +1339,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_ZCB_AND_ZBA,  "Cs,Cw", MATCH_C_ZEXT_W, MASK_C_ZEXT_W, match_opcode, INSN_ALIAS | INSN_NON_EXACT },
 {"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, NULL, INSN_MACRO },
 {"add.uw",    64, INSN_CLASS_ZBA,  "d,s,t", MATCH_ADD_UW, MASK_ADD_UW, match_opcode, 0 },
-- 
2.43.0



More information about the Binutils mailing list