[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