[2/3] RISC-V: Fallback on faster hash table

Message ID e984efaf6c2d42891fa466338d999bf8b292dd7d.1668906514.git.research_trasio@irq.a4lg.com
State Unresolved
Headers
Series RISC-V: Disassembler Core Optimization 1-1 (Hash table and Caching) |

Checks

Context Check Description
snail/binutils-gdb-check warning Git am fail log

Commit Message

Tsukasa OI Nov. 20, 2022, 1:08 a.m. UTC
  From: Tsukasa OI <research_trasio@irq.a4lg.com>

Although it does not have a problem on current GNU Binutils implementation,
if the custom vendor implements an instruction which spans across multiple
major opcodes (e.g. uses both CUSTOM_0 and CUSTOM_1 in a *single* custom
instruction), the original assumption of the sorted hash table breaks.

In this case, this commit enables the fallback mode to disable all
optimizations except filtering macros out.

Note that, if a such instruction (that disables this disassembler
optimization) is upstreamed to Binutils, a separate solution will be
required to avoid major performance degradation when such instruction is
not used.  The intent of this commit is to make a room for custom vendors
to implement such instructions in *their* tree without causing
disassembler problems.

opcodes/ChangeLog:

	* riscv-dis.c (is_riscv_hash_fallback) New.
	(build_riscv_opcodes_hash_table): If an instruction spans across
	multiple major opcodes, enable fallback mode and disable sorting.
	(riscv_disassemble_insn): If the fallback mode is enabled, scan
	through all instructions instead of scanning only instruction
	entries matching the hash value.
---
 opcodes/riscv-dis.c | 31 ++++++++++++++++++++++++++-----
 1 file changed, 26 insertions(+), 5 deletions(-)
  

Patch

diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c
index a4a74e5733a5..197f6a31d439 100644
--- a/opcodes/riscv-dis.c
+++ b/opcodes/riscv-dis.c
@@ -838,6 +838,9 @@  print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
 static const struct riscv_opcode **riscv_hash[OP_HASH_LEN + 1];
 static const struct riscv_opcode **riscv_opcodes_sorted;
 
+/* Whether the fallback should be used.  */
+static bool is_riscv_hash_fallback = false;
+
 /* Compare two riscv_opcode* objects to sort by hash index.  */
 
 static int
@@ -868,15 +871,25 @@  build_riscv_opcodes_hash_table (void)
 
   /* Sort riscv_opcodes entry pointers (except macros).  */
   for (op = riscv_opcodes; op->name; op++)
-    if (op->pinfo != INSN_MACRO)
+    {
+      if (op->pinfo == INSN_MACRO)
+	continue;
       len++;
+      if (is_riscv_hash_fallback)
+	continue;
+      if (OP_HASH_IDX (op->match) < OP_MASK_OP2
+	      ? (op->mask & OP_MASK_OP2) != OP_MASK_OP2
+	      : (op->mask & OP_MASK_OP)  != OP_MASK_OP)
+	is_riscv_hash_fallback = true;
+    }
   riscv_opcodes_sorted = xcalloc (len, sizeof (struct riscv_opcode *));
   pop_end = riscv_opcodes_sorted;
   for (op = riscv_opcodes; op->name; op++)
     if (op->pinfo != INSN_MACRO)
       *pop_end++ = op;
-  qsort (riscv_opcodes_sorted, len, sizeof (struct riscv_opcode *),
-	 compare_opcodes);
+  if (!is_riscv_hash_fallback)
+    qsort (riscv_opcodes_sorted, len, sizeof (struct riscv_opcode *),
+	   compare_opcodes);
 
   /* Initialize faster hash table.  */
   pop = riscv_opcodes_sorted;
@@ -919,8 +932,16 @@  riscv_disassemble_insn (bfd_vma memaddr, insn_t word, disassemble_info *info)
   info->target2 = 0;
 
   matched_op = NULL;
-  pop     = riscv_hash[OP_HASH_IDX (word)];
-  pop_end = riscv_hash[OP_HASH_IDX (word) + 1];
+  if (!is_riscv_hash_fallback)
+    {
+      pop     = riscv_hash[OP_HASH_IDX (word)];
+      pop_end = riscv_hash[OP_HASH_IDX (word) + 1];
+    }
+  else
+    {
+      pop     = riscv_hash[0];
+      pop_end = riscv_hash[OP_HASH_LEN];
+    }
   for (; pop != pop_end; pop++)
     {
       op = *pop;