[PATCH 5/6] aarch64: Use an enum to refer to indices in the opcode table
Richard Earnshaw (lists)
Richard.Earnshaw@arm.com
Mon Jul 21 17:11:47 GMT 2025
On 18/07/2025 16:34, Alice Carlotti wrote:
> On Fri, Jul 18, 2025 at 11:04:00AM +0100, Richard Earnshaw wrote:
>> $(AM_V_GEN)./aarch64-gen$(exeext_for_build) --gen-opc > $@
>> +$(srcdir)/aarch64-tbl-2.h: @MAINT@ aarch64-gen$(exeext_for_build)
>> + $(AM_V_GEN)./aarch64-gen$(exeext_for_build) --gen-idx > $@
>> +
>> +aarch64-asm-2.lo: $(srcdir)/aarch64-tbl-2.h $(srcdir)/aarch64-asm-2.c
>> +
>> +aarch64-dis-2.lo: $(srcdir)/aarch64-tbl-2.h $(srcdir)/aarch64-dis-2.c
>> +
>> +aarch64-opc-2.lo: $(srcdir)/aarch64-tbl-2.h $(srcdir)/aarch64-opc-2.c
>
> Is it necessary to specify the dependency of the .c files here? I would expect
> it to be handled already by the default build rules.
>
In the strictest sense, probably not. But it seems strange to mention the dependency on aarch64-tbl-2.h and omit the dependency on the main source file itself. It's pretty harmless, so I've left it in.
>> @@ -199,7 +205,8 @@ read_table (const struct aarch64_opcode* table)
>> /* If a subclass is set for one insn of an iclass, every insn of that
>> iclass must have non-zero subclass field. */
>> if ((iclass_has_subclasses_p[ent->iclass] && !(ent->flags & F_SUBCLASS))
>> - || (!iclass_has_subclasses_p[ent->iclass] && (ent->flags & F_SUBCLASS)))
>> + || (!iclass_has_subclasses_p[ent->iclass]
>> + && (ent->flags & F_SUBCLASS)))
>> {
>> fprintf (stderr, "%s: unexpected subclass\n", ent->name);
>> ++errors;
>
> These two hunks appear to be irrelevant formatting changes, so shouldn't be
> part of this patch.
Moved to another patch earlier in the series.
>> @@ -1142,6 +1154,89 @@ print_operand_extractor (void)
>> printf (" }\n");
>> printf ("}\n");
>> }
>> +
>> +/* Generate a set of labels for the opcode table, so that we can refer to index
>> + entries through stable names. The general format for the label is:
>> + <opcode>_<mnemonic>(_operand_name)*
>> + We currently do not need to use the qualifiers to discriminate further, and
>> + hopefully never will. */
>> +#define ENUM_PFX "aa64_opid_"
>
> All the existing enums we have that use prefixed names used AARCH64_[CAPS]_ as
> the prefix. I don't see any reason to do differently here - i.e.
> "AARCH64_OPID_" would be more consistent. Also, with the below suggestions we
> only need one reference to this, so we could just inline the #define.
I've changed it to A64_OPID_ and then embedded it. These enumeration values have very long names (some are around 70 chars), so to keep things a little more manageable I've not used the additional 'ARCH' letters. Technically, A64 is the instruction set used in AArch64, so it's not even wrong :)
>
>> +#define MAX_LABEL_LEN 100
>> +void
>> +label_opcode_nodes (void)
>> +{
>> + unsigned count = sizeof (aarch64_opcode_table) / sizeof (aarch64_opcode);
>> + unsigned i;
>> + const aarch64_opcode *opc;
>> +
>> + opcode_node_labels = malloc (count * sizeof (char *));
>> +
>> + for (i = 0, opc = aarch64_opcode_table; i < count - 1; ++i, ++opc)
>> + {
>> + char buf[MAX_LABEL_LEN];
>> + char *p;
>> + unsigned j;
>> + size_t l;
>> +
>> + strcpy (buf, ENUM_PFX);
>> + p = buf + sizeof(ENUM_PFX) - 1;
>> +
>> + assert (p - buf + 9 < MAX_LABEL_LEN);
>> + sprintf (p, "%08x_", opc->opcode);
>> + p += 9;
>> + l = strlen (opc->name);
>> + assert (p - buf + l < MAX_LABEL_LEN);
>> + strcpy (p, opc->name);
>> + p += l;
>> + for (j = 0;
>> + j < AARCH64_MAX_OPND_NUM && opc->operands[j] != AARCH64_OPND_NIL;
>> + j++)
>> + {
>> + l = strlen (operands[opc->operands[j]].str);
>> + assert (p - buf + 1 + l < MAX_LABEL_LEN);
>> + *(p++) = '_';
>> + strcpy (p, operands[opc->operands[j]].str);
>> + p += l;
>> + }
>
> This feels quite verbose and repetitive with all the separate asserts and
> pointer increments. How about replacing the above with:
>
> char buf[MAX_LABEL_LEN];
> char *p = buf;
> p += snprintf (p, "AARCH64_OPID_%08x_%s", MAX_LABEL_LEN, opc->opcode,
> opc->name);
> assert (p < buf + MAX_LABEL_LEN);
>
> for (...)
> {
> p + snprintf (p, "_%s", buf + MAX_LABEL_LEN - p, operands[opc->operands[j]].str);
> assert (p < buf + MAX_LABEL_LEN);
> }
>
Fixed, but I've added some code to check for snprintf returning negative values as well.
>> +
>> + /* Sanitize the opcode name into something that can be used as
>> + an identifier. */
>> + for (p = buf + sizeof (ENUM_PFX) + 9; *p != '\0'; ++p)
>
> It would be clearer to just sanitise the whole string without skipping past the
> initial segment.
Agreed, fixed.
>
>> + if (!(isalpha (*p) || isdigit (*p) || *p == '_'))
>> + *p = '_';
>> +
>> + opcode_node_labels[i] = strdup (buf);
>> + }
>> +
>> + opcode_node_labels[i] = ENUM_PFX "max";
>
> We can write this explicitly as "AARCH64_OPID_MAX" and drop the #define.
>
Fixed, but see above.
>> +}
>> +
>> +/* Emit the opcode labels as an enum */
>> +void
>> +print_opcode_labels_defn (void)
>> +{
>> + unsigned count = sizeof (aarch64_opcode_table) / sizeof (aarch64_opcode);
>> + unsigned i;
>> +
>> + printf ("/* Mnemonic names for the indices in the aarch64_opcode table,\n"
>> + " so that we can refer to the entries by name. This serves two\n"
>> + " main purposes. Firstly, the names change rarely, if at all,\n"
>> + " so diffs in the generated files as entries are added to the\n"
>> + " table are much smaller. Secondly, the names are useful when\n"
>> + " viewing the generated code in a debugger, giving a better\n"
>
> You can drop "in a debugger" - it's useful outside a debugger as well.
>
I changed it to 'for example, in a debugger'. It was never meant to mean that was the only place where this might be useful.
>> @@ -1185,18 +1280,19 @@ print_get_opcode (void)
>>
>> /* Print the table. */
>> printf ("\n");
>> - printf ("/* Indexed by an enum aarch64_op enumerator, the value is the offset of\n\
>> - the corresponding aarch64_opcode entry in the aarch64_opcode_table. */\n\n");
>> - printf ("static const unsigned op_enum_table [] =\n");
>> + printf ("/* Indexed by an enum aarch64_op enumerator, the value is the\n"
>> + " offset of the corresponding aarch64_opcode entry in the\n"
>> + " aarch64_opcode_table. */\n\n");
>> + printf ("static const enum aarch64_opcode_idx op_enum_table [] =\n");
>> printf ("{\n");
>> for (i = 0; i < num; ++i)
>> - printf (" %u,\n", op_enum_table[i]);
>> + printf (" %s,\n", opcode_node_labels[op_enum_table[i]]);
>> printf ("};\n");
>>
>> /* Print the function. */
>> printf ("\n");
>> - printf ("/* Given the opcode enumerator OP, return the pointer to the corresponding\n");
>> - printf (" opcode entry. */\n");
>> + printf ("/* Given the opcode enumerator OP, return the pointer to the\n"
>> + " corresponding opcode entry. */\n");
>
> These two comments haven't changed, so the reformatting probably shouldn't be
> part of this patch.
Moved to the new cleanup patch.
R.
More information about the Binutils
mailing list