Skip to content

Commit 85dabed

Browse files
committed
RISC-V: Reorganize disassembler state initialization
The current disassembler repeatedly checks current state per instruction: - Whether riscv_gpr_names is initialized to a non-NULL value - Whether the Zfinx extension is available - Whether the hash table is initialized ... but they are not frequently changed. riscv_gpr_names is initialized to a non-NULL value when - The first disassembler option is specified, or - Not initialized with disassembler options (in the first print_insn_riscv function call). We can safely initialize the default disassembler options prior to the print_insn_riscv function call and this per-instruction checking of riscv_gpr_names can be safely removed. The opcode hash table initialization will be taken care with a later commit. To group disassembler state initialization, this commit utilizes the disassemble_init_for_target function. As a side effect, this will also fix a potential issue when disassembler options is set and then unset on GDB. This idea is based on opcodes/ppc-dis.c and opcodes/wasm32-dis.c. New callback function init_riscv_dis_state_for_arch_and_options is called when either the architecture string or an option is possibly changed. We can now group the disassembler state initialization together. It makes state initialization clearer and makes further changes easier. In performance perspective, this commit has various effects (-5% to 6%). However, this commit makes implementing large optimizations easier as well as "RISC-V: Split match/print steps on disassembler". include/ChangeLog: * dis-asm.h (disassemble_init_riscv): Add declaration of disassemble_init_riscv. opcodes/ChangeLog: * disassemble.c (disassemble_init_for_target): Call disassemble_init_riscv to group state initialization together. * riscv-dis.c (xlen_by_mach, xlen_by_elf): New variables to store environment-inferred XLEN. (is_numeric): New. Instead of directly setting riscv_{gpr,fpr}_names, use this to store an option. (update_riscv_dis_xlen): New function to set actual XLEN from xlen_by_mach and xlen_by_elf variables. (init_riscv_dis_state_for_arch_and_options): New callback function called when either the architecture or an option is changed. Set riscv_{gpr,fpr}_names here. (set_default_riscv_dis_options): Initialize is_numeric instead of riscv_gpr_names and riscv_fpr_names. (parse_riscv_dis_option_without_args): When the "numeric" option is specified, write to is_numeric instead of register names. (parse_riscv_dis_options): Suppress setting the default options here and let disassemble_init_riscv to initialize them. (riscv_disassemble_insn): Move probing Zfinx and setting XLEN portions to init_riscv_dis_state_for_arch_and_options and update_riscv_dis_xlen. (riscv_get_map_state): If a mapping symbol with ISA string is suitable, call init_riscv_dis_state_for_arch_and_options function to update disassembler state. (print_insn_riscv): Update XLEN only if we haven't guessed correct XLEN for the disassembler. Stop checking disassembler options for every instruction and let disassemble_init_riscv to parse options. (riscv_get_disassembler): Call init_riscv_dis_state_for_arch_and_options because the architecture string is updated here. (disassemble_init_riscv): New function to initialize the structure, reset/guess correct XLEN and reset/parse disassembler options.
1 parent ccdff54 commit 85dabed

File tree

3 files changed

+79
-36
lines changed

3 files changed

+79
-36
lines changed

include/dis-asm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ extern bool arm_symbol_is_valid (asymbol *, struct disassemble_info *);
393393
extern bool csky_symbol_is_valid (asymbol *, struct disassemble_info *);
394394
extern bool riscv_symbol_is_valid (asymbol *, struct disassemble_info *);
395395
extern void disassemble_init_powerpc (struct disassemble_info *);
396+
extern void disassemble_init_riscv (struct disassemble_info *);
396397
extern void disassemble_init_s390 (struct disassemble_info *);
397398
extern void disassemble_init_wasm32 (struct disassemble_info *);
398399
extern void disassemble_init_nds32 (struct disassemble_info *);

opcodes/disassemble.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,7 @@ disassemble_init_for_target (struct disassemble_info * info)
717717
#endif
718718
#ifdef ARCH_riscv
719719
case bfd_arch_riscv:
720-
info->symbol_is_valid = riscv_symbol_is_valid;
720+
disassemble_init_riscv (info);
721721
info->created_styled_output = true;
722722
break;
723723
#endif

opcodes/riscv-dis.c

Lines changed: 77 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@
3535
/* Current XLEN for the disassembler. */
3636
static unsigned xlen = 0;
3737

38+
/* XLEN as inferred by the machine architecture. */
39+
static unsigned xlen_by_mach = 0;
40+
41+
/* XLEN as inferred by ELF header. */
42+
static unsigned xlen_by_elf = 0;
43+
3844
/* Default ISA specification version (constant as of now). */
3945
static enum riscv_spec_class default_isa_spec = ISA_SPEC_CLASS_DRAFT - 1;
4046

@@ -72,16 +78,57 @@ static const char * const *riscv_fpr_names;
7278

7379
/* If set, disassemble as most general instruction. */
7480
static bool no_aliases = false;
81+
82+
/* If set, disassemble with numeric register names. */
83+
static bool is_numeric = false;
84+
85+
86+
/* Guess and update current XLEN. */
87+
88+
static void
89+
update_riscv_dis_xlen (struct disassemble_info *info)
90+
{
91+
/* Set XLEN with following precedence rules:
92+
1. BFD machine architecture set by either:
93+
a. -m riscv:rv[32|64] option (GDB: set arch riscv:rv[32|64])
94+
b. ELF class in actual ELF header (only on RISC-V ELF)
95+
This is only effective if XLEN-specific BFD machine architecture is
96+
chosen. If XLEN-neutral (like riscv), BFD machine architecture is
97+
ignored on XLEN selection.
98+
2. ELF class in dummy ELF header. */
99+
if (xlen_by_mach != 0)
100+
xlen = xlen_by_mach;
101+
else if (xlen_by_elf != 0)
102+
xlen = xlen_by_elf;
103+
else if (info != NULL && info->section != NULL)
104+
{
105+
Elf_Internal_Ehdr *ehdr = elf_elfheader (info->section->owner);
106+
xlen = xlen_by_elf = ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? 64 : 32;
107+
}
108+
}
109+
110+
/* Initialization (for arch and options). */
111+
112+
static void
113+
init_riscv_dis_state_for_arch_and_options (void)
114+
{
115+
/* Set GPR register names to disassemble. */
116+
riscv_gpr_names = is_numeric ? riscv_gpr_names_numeric : riscv_gpr_names_abi;
117+
/* Set FPR register names to disassemble. */
118+
riscv_fpr_names
119+
= !riscv_subset_supports (&riscv_rps_dis, "zfinx")
120+
? (is_numeric ? riscv_fpr_names_numeric : riscv_fpr_names_abi)
121+
: riscv_gpr_names;
122+
}
75123

76124

77125
/* Set default RISC-V disassembler options. */
78126

79127
static void
80128
set_default_riscv_dis_options (void)
81129
{
82-
riscv_gpr_names = riscv_gpr_names_abi;
83-
riscv_fpr_names = riscv_fpr_names_abi;
84130
no_aliases = false;
131+
is_numeric = false;
85132
}
86133

87134
/* Parse RISC-V disassembler option (without arguments). */
@@ -92,10 +139,7 @@ parse_riscv_dis_option_without_args (const char *option)
92139
if (strcmp (option, "no-aliases") == 0)
93140
no_aliases = true;
94141
else if (strcmp (option, "numeric") == 0)
95-
{
96-
riscv_gpr_names = riscv_gpr_names_numeric;
97-
riscv_fpr_names = riscv_fpr_names_numeric;
98-
}
142+
is_numeric = true;
99143
else
100144
return false;
101145
return true;
@@ -163,8 +207,6 @@ parse_riscv_dis_options (const char *opts_in)
163207
{
164208
char *opts = xstrdup (opts_in), *opt = opts, *opt_end = opts;
165209

166-
set_default_riscv_dis_options ();
167-
168210
for ( ; opt_end != NULL; opt = opt_end + 1)
169211
{
170212
if ((opt_end = strchr (opt, ',')) != NULL)
@@ -705,25 +747,6 @@ riscv_disassemble_insn (bfd_vma memaddr, insn_t word, disassemble_info *info)
705747
matched_op = NULL;
706748
op = riscv_hash[OP_HASH_IDX (word)];
707749

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-
}
718-
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;
726-
727750
for (; op && op->name; op++)
728751
{
729752
/* Does the opcode match? */
@@ -867,6 +890,7 @@ riscv_get_map_state (int n,
867890
{
868891
riscv_release_subset_list (&riscv_subsets);
869892
riscv_parse_subset (&riscv_rps_dis, arch);
893+
init_riscv_dis_state_for_arch_and_options ();
870894
}
871895
return true;
872896
}
@@ -1063,14 +1087,9 @@ print_insn_riscv (bfd_vma memaddr, struct disassemble_info *info)
10631087
enum riscv_seg_mstate mstate;
10641088
int (*riscv_disassembler) (bfd_vma, insn_t, struct disassemble_info *);
10651089

1066-
if (info->disassembler_options != NULL)
1067-
{
1068-
parse_riscv_dis_options (info->disassembler_options);
1069-
/* Avoid repeatedly parsing the options. */
1070-
info->disassembler_options = NULL;
1071-
}
1072-
else if (riscv_gpr_names == NULL)
1073-
set_default_riscv_dis_options ();
1090+
/* Guess and update XLEN if we haven't determined it yet. */
1091+
if (xlen == 0)
1092+
update_riscv_dis_xlen (info);
10741093

10751094
mstate = riscv_search_mapping_symbol (memaddr, info);
10761095

@@ -1132,9 +1151,32 @@ riscv_get_disassembler (bfd *abfd)
11321151

11331152
riscv_release_subset_list (&riscv_subsets);
11341153
riscv_parse_subset (&riscv_rps_dis, default_arch);
1154+
init_riscv_dis_state_for_arch_and_options ();
11351155
return print_insn_riscv;
11361156
}
11371157

1158+
/* Initialize disassemble_info and parse options. */
1159+
1160+
void
1161+
disassemble_init_riscv (struct disassemble_info *info)
1162+
{
1163+
info->symbol_is_valid = riscv_symbol_is_valid;
1164+
/* Clear previous XLEN and guess by mach. */
1165+
xlen = 0;
1166+
xlen_by_mach = 0;
1167+
xlen_by_elf = 0;
1168+
if (info->mach == bfd_mach_riscv64)
1169+
xlen_by_mach = 64;
1170+
else if (info->mach == bfd_mach_riscv32)
1171+
xlen_by_mach = 32;
1172+
update_riscv_dis_xlen (info);
1173+
/* Parse disassembler options. */
1174+
set_default_riscv_dis_options ();
1175+
if (info->disassembler_options != NULL)
1176+
parse_riscv_dis_options (info->disassembler_options);
1177+
init_riscv_dis_state_for_arch_and_options ();
1178+
}
1179+
11381180
/* Prevent use of the fake labels that are generated as part of the DWARF
11391181
and for relaxable relocations in the assembler. */
11401182

0 commit comments

Comments
 (0)