Skip to content

Commit a7a665b

Browse files
committed
RISC-V: Split match/print steps on disassembler
For further optimization and more disassembler features, we may need to change the core RISC-V instruction matching. For this purpose, it is inconvenient to have "match" and "print" steps in the same loop. This commit rewrites riscv_disassemble_insn function so that we store matched_op for matching RISC-V opcode and then print it (if not NULL). Although it looks a bit inefficient, it also lowers the indent of opcode matching loop to clarify the opcode matching changes on the next optimization commit. Unfortunately, this commit alone will impose some performance penalty (<5% on most cases but sometimes about 15% worse) but it can be easily paid back by other optimizations. opcodes/ChangeLog: * riscv-dis.c (riscv_disassemble_insn): Split instruction handling to two separate steps - opcode matching and printing.
1 parent 276d094 commit a7a665b

File tree

1 file changed

+77
-70
lines changed

1 file changed

+77
-70
lines changed

opcodes/riscv-dis.c

Lines changed: 77 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,7 @@ riscv_disassemble_insn (bfd_vma memaddr,
707707
const bfd_byte *packet,
708708
disassemble_info *info)
709709
{
710-
const struct riscv_opcode *op;
710+
const struct riscv_opcode *op, *matched_op;
711711
static bool init = false;
712712
static const struct riscv_opcode *riscv_hash[OP_MASK_OP + 1];
713713
struct riscv_private_data *pd = info->private_data;
@@ -742,85 +742,92 @@ riscv_disassemble_insn (bfd_vma memaddr,
742742
info->target = 0;
743743
info->target2 = 0;
744744

745+
matched_op = NULL;
745746
op = riscv_hash[OP_HASH_IDX (word)];
746-
if (op != NULL)
747+
748+
/* If XLEN is not known, get its value from the ELF class. */
749+
if (info->mach == bfd_mach_riscv64)
750+
xlen = 64;
751+
else if (info->mach == bfd_mach_riscv32)
752+
xlen = 32;
753+
else if (info->section != NULL)
747754
{
748-
/* If XLEN is not known, get its value from the ELF class. */
749-
if (info->mach == bfd_mach_riscv64)
750-
xlen = 64;
751-
else if (info->mach == bfd_mach_riscv32)
752-
xlen = 32;
753-
else if (info->section != NULL)
754-
{
755-
Elf_Internal_Ehdr *ehdr = elf_elfheader (info->section->owner);
756-
xlen = ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? 64 : 32;
757-
}
755+
Elf_Internal_Ehdr *ehdr = elf_elfheader (info->section->owner);
756+
xlen = ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? 64 : 32;
757+
}
758758

759-
/* If arch has the Zfinx extension, replace FPR with GPR. */
760-
if (riscv_subset_supports (&riscv_rps_dis, "zfinx"))
761-
riscv_fpr_names = riscv_gpr_names;
762-
else
763-
riscv_fpr_names = riscv_gpr_names == riscv_gpr_names_abi ?
764-
riscv_fpr_names_abi : riscv_fpr_names_numeric;
759+
/* If arch has the Zfinx extension, replace FPR with GPR. */
760+
if (riscv_subset_supports (&riscv_rps_dis, "zfinx"))
761+
riscv_fpr_names = riscv_gpr_names;
762+
else
763+
riscv_fpr_names = riscv_gpr_names == riscv_gpr_names_abi
764+
? riscv_fpr_names_abi
765+
: riscv_fpr_names_numeric;
765766

766-
for (; op->name; op++)
767-
{
768-
/* Does the opcode match? */
769-
if (! (op->match_func) (op, word))
770-
continue;
771-
/* Is this a pseudo-instruction and may we print it as such? */
772-
if (no_aliases && (op->pinfo & INSN_ALIAS))
773-
continue;
774-
/* Is this instruction restricted to a certain value of XLEN? */
775-
if ((op->xlen_requirement != 0) && (op->xlen_requirement != xlen))
776-
continue;
777-
/* Is this instruction supported by the current architecture? */
778-
if (!riscv_multi_subset_supports (&riscv_rps_dis, op->insn_class))
779-
continue;
767+
for (; op && op->name; op++)
768+
{
769+
/* Does the opcode match? */
770+
if (!(op->match_func) (op, word))
771+
continue;
772+
/* Is this a pseudo-instruction and may we print it as such? */
773+
if (no_aliases && (op->pinfo & INSN_ALIAS))
774+
continue;
775+
/* Is this instruction restricted to a certain value of XLEN? */
776+
if ((op->xlen_requirement != 0) && (op->xlen_requirement != xlen))
777+
continue;
778+
/* Is this instruction supported by the current architecture? */
779+
if (!riscv_multi_subset_supports (&riscv_rps_dis, op->insn_class))
780+
continue;
780781

781-
/* It's a match. */
782-
(*info->fprintf_styled_func) (info->stream, dis_style_mnemonic,
783-
"%s", op->name);
784-
print_insn_args (op->args, word, memaddr, info);
782+
matched_op = op;
783+
break;
784+
}
785785

786-
/* Try to disassemble multi-instruction addressing sequences. */
787-
if (pd->to_print_addr)
788-
{
789-
info->target = pd->print_addr;
790-
(*info->fprintf_styled_func)
791-
(info->stream, dis_style_comment_start, " # ");
792-
(*info->print_address_func) (info->target, info);
793-
pd->to_print_addr = false;
794-
}
786+
if (matched_op != NULL)
787+
{
788+
/* There is a match. */
789+
op = matched_op;
795790

796-
/* Finish filling out insn_info fields. */
797-
switch (op->pinfo & INSN_TYPE)
798-
{
799-
case INSN_BRANCH:
800-
info->insn_type = dis_branch;
801-
break;
802-
case INSN_CONDBRANCH:
803-
info->insn_type = dis_condbranch;
804-
break;
805-
case INSN_JSR:
806-
info->insn_type = dis_jsr;
807-
break;
808-
case INSN_DREF:
809-
info->insn_type = dis_dref;
810-
break;
811-
default:
812-
break;
813-
}
791+
(*info->fprintf_styled_func) (info->stream, dis_style_mnemonic,
792+
"%s", op->name);
793+
print_insn_args (op->args, word, memaddr, info);
814794

815-
if (op->pinfo & INSN_DATA_SIZE)
816-
{
817-
int size = ((op->pinfo & INSN_DATA_SIZE)
818-
>> INSN_DATA_SIZE_SHIFT);
819-
info->data_size = 1 << (size - 1);
820-
}
795+
/* Try to disassemble multi-instruction addressing sequences. */
796+
if (pd->to_print_addr)
797+
{
798+
info->target = pd->print_addr;
799+
(*info->fprintf_styled_func) (info->stream, dis_style_comment_start,
800+
" # ");
801+
(*info->print_address_func) (info->target, info);
802+
pd->to_print_addr = false;
803+
}
821804

822-
return insnlen;
805+
/* Finish filling out insn_info fields. */
806+
switch (op->pinfo & INSN_TYPE)
807+
{
808+
case INSN_BRANCH:
809+
info->insn_type = dis_branch;
810+
break;
811+
case INSN_CONDBRANCH:
812+
info->insn_type = dis_condbranch;
813+
break;
814+
case INSN_JSR:
815+
info->insn_type = dis_jsr;
816+
break;
817+
case INSN_DREF:
818+
info->insn_type = dis_dref;
819+
break;
820+
default:
821+
break;
823822
}
823+
824+
if (op->pinfo & INSN_DATA_SIZE)
825+
{
826+
int size = ((op->pinfo & INSN_DATA_SIZE) >> INSN_DATA_SIZE_SHIFT);
827+
info->data_size = 1 << (size - 1);
828+
}
829+
830+
return insnlen;
824831
}
825832

826833
/* We did not find a match, so just print the instruction bits in

0 commit comments

Comments
 (0)