Skip to content

Commit 2dd0a79

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 ebc57c3 commit 2dd0a79

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
@@ -702,7 +702,7 @@ riscv_disassemble_insn (bfd_vma memaddr,
702702
const bfd_byte *packet,
703703
disassemble_info *info)
704704
{
705-
const struct riscv_opcode *op;
705+
const struct riscv_opcode *op, *matched_op;
706706
static bool init = false;
707707
static const struct riscv_opcode *riscv_hash[OP_MASK_OP + 1];
708708
struct riscv_private_data *pd = info->private_data;
@@ -737,85 +737,92 @@ riscv_disassemble_insn (bfd_vma memaddr,
737737
info->target = 0;
738738
info->target2 = 0;
739739

740+
matched_op = NULL;
740741
op = riscv_hash[OP_HASH_IDX (word)];
741-
if (op != NULL)
742+
743+
/* If XLEN is not known, get its value from the ELF class. */
744+
if (info->mach == bfd_mach_riscv64)
745+
xlen = 64;
746+
else if (info->mach == bfd_mach_riscv32)
747+
xlen = 32;
748+
else if (info->section != NULL)
742749
{
743-
/* If XLEN is not known, get its value from the ELF class. */
744-
if (info->mach == bfd_mach_riscv64)
745-
xlen = 64;
746-
else if (info->mach == bfd_mach_riscv32)
747-
xlen = 32;
748-
else if (info->section != NULL)
749-
{
750-
Elf_Internal_Ehdr *ehdr = elf_elfheader (info->section->owner);
751-
xlen = ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? 64 : 32;
752-
}
750+
Elf_Internal_Ehdr *ehdr = elf_elfheader (info->section->owner);
751+
xlen = ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? 64 : 32;
752+
}
753753

754-
/* If arch has the Zfinx extension, replace FPR with GPR. */
755-
if (riscv_subset_supports (&riscv_rps_dis, "zfinx"))
756-
riscv_fpr_names = riscv_gpr_names;
757-
else
758-
riscv_fpr_names = riscv_gpr_names == riscv_gpr_names_abi ?
759-
riscv_fpr_names_abi : riscv_fpr_names_numeric;
754+
/* If arch has the Zfinx extension, replace FPR with GPR. */
755+
if (riscv_subset_supports (&riscv_rps_dis, "zfinx"))
756+
riscv_fpr_names = riscv_gpr_names;
757+
else
758+
riscv_fpr_names = riscv_gpr_names == riscv_gpr_names_abi
759+
? riscv_fpr_names_abi
760+
: riscv_fpr_names_numeric;
760761

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

776-
/* It's a match. */
777-
(*info->fprintf_styled_func) (info->stream, dis_style_mnemonic,
778-
"%s", op->name);
779-
print_insn_args (op->args, word, memaddr, info);
777+
matched_op = op;
778+
break;
779+
}
780780

781-
/* Try to disassemble multi-instruction addressing sequences. */
782-
if (pd->to_print_addr)
783-
{
784-
info->target = pd->print_addr;
785-
(*info->fprintf_styled_func)
786-
(info->stream, dis_style_comment_start, " # ");
787-
(*info->print_address_func) (info->target, info);
788-
pd->to_print_addr = false;
789-
}
781+
if (matched_op != NULL)
782+
{
783+
/* There is a match. */
784+
op = matched_op;
790785

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

810-
if (op->pinfo & INSN_DATA_SIZE)
811-
{
812-
int size = ((op->pinfo & INSN_DATA_SIZE)
813-
>> INSN_DATA_SIZE_SHIFT);
814-
info->data_size = 1 << (size - 1);
815-
}
790+
/* Try to disassemble multi-instruction addressing sequences. */
791+
if (pd->to_print_addr)
792+
{
793+
info->target = pd->print_addr;
794+
(*info->fprintf_styled_func) (info->stream, dis_style_comment_start,
795+
" # ");
796+
(*info->print_address_func) (info->target, info);
797+
pd->to_print_addr = false;
798+
}
816799

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

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

0 commit comments

Comments
 (0)