[PATCH 1/9] aarch64: Extend aarch64_field to support constants

Richard Earnshaw (lists) Richard.Earnshaw@arm.com
Wed Oct 8 12:22:03 GMT 2025


On 08/10/2025 12:49, Alice Carlotti wrote:
> 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?

I think that would be a good idea.  Anything that is not immediately apparent really should have the interface described explicitly.

> 
>>
>> 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.
> 
I'd use unsigned int if you're using bitfields.  There's no particular benefit to using char and then you can use whatever order seems the most logical.

But I might be inclined to use a macro for the initializers anyway, and that can expand to the fields in whatever order is most appropriate.

struct aarch64_field aarch64_fields[] = 
  AARCH64_FIELD_NIL,
  AARCH64_FIELD_CONST (0, 1),   /* CONST_0.  */
  AARCH64_FIELD_CONST (1, 1),   /* CONST_1.  */
  AARCH64_FIELD_VAL (8, 4),     /* Crm: in the system instructions.  */
...
};

Or whatever macro names make the most sense.  The macros can insert 0's for other fields that don't care.

The alternative would be to use designated initializers, but I think the macros are better (they could still use designated initializers if that would help).

R.


> 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