[PATCH 1/9] aarch64: Extend aarch64_field to support constants
Alice Carlotti
alice.carlotti@arm.com
Wed Oct 8 11:49:58 GMT 2025
On Wed, Oct 08, 2025 at 11:56:23AM +0100, Richard Earnshaw (lists) wrote:
> On 08/10/2025 11:34, Alice Carlotti wrote:
> > On Wed, Oct 08, 2025 at 11:17:21AM +0100, Richard Earnshaw (lists) wrote:
> >> On 08/10/2025 01:38, Alice Carlotti wrote:
> >>> Many instructions have constraints on the range of registers they can
> >>> use. This means that some bits in the register number are fixed, and
> >>> therefore aren't mapped to a field in the instruction encoding.
> >>> Currently we use various adhoc rules to handle these fixed bits, but
> >>> this doesn't handle all cases and we often have to write new code to
> >>> support new combinations of permitted registers.
> >>>
> >>> This patch allows these constant bits to instead be specified in the
> >>> same structure used to represent instruction fields. Uses of the new
> >>> constant fields will be introduced in subsequent patches.
> >>
> >> I'm likely missing something, but it would be nice if there were some explanation of how to use this feature in the comments.
> >>
> >> For example, how would I express a even numbered register? an odd-numbered register or a register in the first 16 of a 32-register set? Can I express things like an odd numbered register that is in the range 0-16 (ie one bit set and one bit clear)?
> >
> > There are lots of examples in patches 2, 3, 4, 6 and 7 in this series, that
> > answer all your questions and more. Would you consider that to be enough
> > documentation? I'll note that we don't have a detailed explanation of how the
> > existing field definitions work either, but I think it's pretty clear from the
> > struct elements and existing usage.
>
> Not really. I think this should be properly described in aarch64-opc.h where aarch64_field is defined.
Ok, do you also want me to add an explanation of how the existing field
definitions are used at the same time?
>
> But this brings up another question, why did you do it this way rather than by adding another field to this type for the
> additional information? We don't need these fields to be 32-bit ints, unsigned char would be more than adequate.
Good question. This reflects a step towards how I want to pack the entire
struct into 16 bits in future, but I realise I can just go straight to using a
struct with bitfields already (and I checked that this is passed in a single
register for function calls).
I had planned to use the layout:
struct aarch64_field
{
unsigned char width;
unsigned char value:5;
unsigned char is_constant:1;
};
but this has the downside of requiring all the existing initialised to be swapped. So I think it might be best to instead use:
struct aarch64_field
{
unsigned char value;
unsigned char width:6;
unsigned char is_constant:1;
};
I'll send a new version of this patch later.
Alice
>
> R.
>
> >
> > Alice
> >
> >>
> >> R.
> >>
> >>>
> >>>
> >>> diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
> >>> index 4b173201e92bc7fd5c6d4e306e1f8fb332b0e041..b0ee3c9d3633075377ca3c14feccc124d0a94ba4 100644
> >>> --- a/opcodes/aarch64-opc.c
> >>> +++ b/opcodes/aarch64-opc.c
> >>> @@ -226,6 +226,8 @@ aarch64_select_operand_for_sizeq_field_coding (const aarch64_opcode *opcode)
> >>> const aarch64_field aarch64_fields[] =
> >>> {
> >>> { 0, 0 }, /* NIL. */
> >>> + { 32, 1 }, /* CONST_0. */
> >>> + { 33, 1 }, /* CONST_1. */
> >>> { 8, 4 }, /* CRm: in the system instructions. */
> >>> { 10, 2 }, /* CRm_dsb_nxs: 2-bit imm. encoded in CRm<3:2>. */
> >>> { 12, 4 }, /* CRn: in the system instructions. */
> >>> diff --git a/opcodes/aarch64-opc.h b/opcodes/aarch64-opc.h
> >>> index 4182c9d5f678beac3a240e08c9842e8620a32bb6..4d2d928c1d8d39b9489e073fc9141c154b38e3a3 100644
> >>> --- a/opcodes/aarch64-opc.h
> >>> +++ b/opcodes/aarch64-opc.h
> >>> @@ -30,6 +30,8 @@
> >>> enum aarch64_field_kind
> >>> {
> >>> FLD_NIL,
> >>> + FLD_CONST_0,
> >>> + FLD_CONST_1,
> >>> FLD_CRm,
> >>> FLD_CRm_dsb_nxs,
> >>> FLD_CRn,
> >>> @@ -242,7 +244,10 @@ enum aarch64_field_kind
> >>> FLD_ZA5_4,
> >>> };
> >>>
> >>> -/* Field description. */
> >>> +/* Field description.
> >>> + If lsb < 32, then this represents a field in an instruction encoding.
> >>> + If lsb >= 32, then this represents a constant value of width <= 5,
> >>> + stored as lsb = (value | 32). */
> >>> struct aarch64_field
> >>> {
> >>> int lsb;
> >>> @@ -497,8 +502,14 @@ insert_field_2 (const aarch64_field *field, aarch64_insn *code,
> >>> aarch64_insn value, aarch64_insn mask)
> >>> {
> >>> assert (field->width < 32 && field->width >= 1 && field->lsb >= 0
> >>> - && field->lsb + field->width <= 32);
> >>> + && (field->lsb >= 32 || (field->lsb + field->width <= 32)));
> >>> value &= gen_mask (field->width);
> >>> + if (field->lsb >= 32)
> >>> + {
> >>> + /* Value is constant. */
> >>> + assert (value == (field->lsb & 31));
> >>> + return;
> >>> + }
> >>> value <<= field->lsb;
> >>> /* In some opcodes, field can be part of the base opcode, e.g. the size
> >>> field in FADD. The following helps avoid corrupt the base opcode. */
> >>> @@ -514,6 +525,10 @@ extract_field_2 (const aarch64_field *field, aarch64_insn code,
> >>> aarch64_insn mask)
> >>> {
> >>> aarch64_insn value;
> >>> + /* Check for constant field. */
> >>> + if (field->lsb >= 32)
> >>> + return field->lsb & 31;
> >>> +
> >>> /* Clear any bit that is a part of the base opcode. */
> >>> code &= ~mask;
> >>> value = (code >> field->lsb) & gen_mask (field->width);
> >>
>
More information about the Binutils
mailing list