Skip to content

Commit a804ad4

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 cae76b7 commit a804ad4

File tree

1 file changed

+79
-72
lines changed

1 file changed

+79
-72
lines changed

opcodes/riscv-dis.c

Lines changed: 79 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,7 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
646646
static int
647647
riscv_disassemble_insn (bfd_vma memaddr, insn_t word, disassemble_info *info)
648648
{
649-
const struct riscv_opcode *op;
649+
const struct riscv_opcode *op, *matched_op;
650650
static bool init = false;
651651
static const struct riscv_opcode *riscv_hash[OP_MASK_OP + 1];
652652
struct riscv_private_data *pd;
@@ -702,85 +702,92 @@ riscv_disassemble_insn (bfd_vma memaddr, insn_t word, disassemble_info *info)
702702
info->target = 0;
703703
info->target2 = 0;
704704

705+
matched_op = NULL;
705706
op = riscv_hash[OP_HASH_IDX (word)];
706-
if (op != NULL)
707+
708+
/* If XLEN is not known, get its value from the ELF class. */
709+
if (info->mach == bfd_mach_riscv64)
710+
xlen = 64;
711+
else if (info->mach == bfd_mach_riscv32)
712+
xlen = 32;
713+
else if (info->section != NULL)
707714
{
708-
/* If XLEN is not known, get its value from the ELF class. */
709-
if (info->mach == bfd_mach_riscv64)
710-
xlen = 64;
711-
else if (info->mach == bfd_mach_riscv32)
712-
xlen = 32;
713-
else if (info->section != NULL)
714-
{
715-
Elf_Internal_Ehdr *ehdr = elf_elfheader (info->section->owner);
716-
xlen = ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? 64 : 32;
717-
}
715+
Elf_Internal_Ehdr *ehdr = elf_elfheader (info->section->owner);
716+
xlen = ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? 64 : 32;
717+
}
718718

719-
/* If arch has the Zfinx extension, replace FPR with GPR. */
720-
if (riscv_subset_supports (&riscv_rps_dis, "zfinx"))
721-
riscv_fpr_names = riscv_gpr_names;
722-
else
723-
riscv_fpr_names = riscv_gpr_names == riscv_gpr_names_abi ?
724-
riscv_fpr_names_abi : riscv_fpr_names_numeric;
719+
/* If arch has the Zfinx extension, replace FPR with GPR. */
720+
if (riscv_subset_supports (&riscv_rps_dis, "zfinx"))
721+
riscv_fpr_names = riscv_gpr_names;
722+
else
723+
riscv_fpr_names = riscv_gpr_names == riscv_gpr_names_abi
724+
? riscv_fpr_names_abi
725+
: riscv_fpr_names_numeric;
725726

726-
for (; op->name; op++)
727-
{
728-
/* Does the opcode match? */
729-
if (! (op->match_func) (op, word))
730-
continue;
731-
/* Is this a pseudo-instruction and may we print it as such? */
732-
if (no_aliases && (op->pinfo & INSN_ALIAS))
733-
continue;
734-
/* Is this instruction restricted to a certain value of XLEN? */
735-
if ((op->xlen_requirement != 0) && (op->xlen_requirement != xlen))
736-
continue;
737-
/* Is this instruction supported by the current architecture? */
738-
if (!riscv_multi_subset_supports (&riscv_rps_dis, op->insn_class))
739-
continue;
740-
741-
/* It's a match. */
742-
(*info->fprintf_styled_func) (info->stream, dis_style_mnemonic,
743-
"%s", op->name);
744-
print_insn_args (op->args, word, memaddr, info);
745-
746-
/* Try to disassemble multi-instruction addressing sequences. */
747-
if (pd->to_print_addr)
748-
{
749-
info->target = pd->print_addr;
750-
(*info->fprintf_styled_func)
751-
(info->stream, dis_style_comment_start, " # ");
752-
(*info->print_address_func) (info->target, info);
753-
pd->to_print_addr = false;
754-
}
727+
for (; op && op->name; op++)
728+
{
729+
/* Does the opcode match? */
730+
if (!(op->match_func) (op, word))
731+
continue;
732+
/* Is this a pseudo-instruction and may we print it as such? */
733+
if (no_aliases && (op->pinfo & INSN_ALIAS))
734+
continue;
735+
/* Is this instruction restricted to a certain value of XLEN? */
736+
if ((op->xlen_requirement != 0) && (op->xlen_requirement != xlen))
737+
continue;
738+
/* Is this instruction supported by the current architecture? */
739+
if (!riscv_multi_subset_supports (&riscv_rps_dis, op->insn_class))
740+
continue;
755741

756-
/* Finish filling out insn_info fields. */
757-
switch (op->pinfo & INSN_TYPE)
758-
{
759-
case INSN_BRANCH:
760-
info->insn_type = dis_branch;
761-
break;
762-
case INSN_CONDBRANCH:
763-
info->insn_type = dis_condbranch;
764-
break;
765-
case INSN_JSR:
766-
info->insn_type = dis_jsr;
767-
break;
768-
case INSN_DREF:
769-
info->insn_type = dis_dref;
770-
break;
771-
default:
772-
break;
773-
}
742+
matched_op = op;
743+
break;
744+
}
774745

775-
if (op->pinfo & INSN_DATA_SIZE)
776-
{
777-
int size = ((op->pinfo & INSN_DATA_SIZE)
778-
>> INSN_DATA_SIZE_SHIFT);
779-
info->data_size = 1 << (size - 1);
780-
}
746+
if (matched_op != NULL)
747+
{
748+
/* There is a match. */
749+
op = matched_op;
750+
751+
(*info->fprintf_styled_func) (info->stream, dis_style_mnemonic,
752+
"%s", op->name);
753+
print_insn_args (op->args, word, memaddr, info);
781754

782-
return insnlen;
755+
/* Try to disassemble multi-instruction addressing sequences. */
756+
if (pd->to_print_addr)
757+
{
758+
info->target = pd->print_addr;
759+
(*info->fprintf_styled_func) (info->stream, dis_style_comment_start,
760+
" # ");
761+
(*info->print_address_func) (info->target, info);
762+
pd->to_print_addr = false;
783763
}
764+
765+
/* Finish filling out insn_info fields. */
766+
switch (op->pinfo & INSN_TYPE)
767+
{
768+
case INSN_BRANCH:
769+
info->insn_type = dis_branch;
770+
break;
771+
case INSN_CONDBRANCH:
772+
info->insn_type = dis_condbranch;
773+
break;
774+
case INSN_JSR:
775+
info->insn_type = dis_jsr;
776+
break;
777+
case INSN_DREF:
778+
info->insn_type = dis_dref;
779+
break;
780+
default:
781+
break;
782+
}
783+
784+
if (op->pinfo & INSN_DATA_SIZE)
785+
{
786+
int size = ((op->pinfo & INSN_DATA_SIZE) >> INSN_DATA_SIZE_SHIFT);
787+
info->data_size = 1 << (size - 1);
788+
}
789+
790+
return insnlen;
784791
}
785792

786793
/* We did not find a match, so just print the instruction bits. */

0 commit comments

Comments
 (0)