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

Alice Carlotti alice.carlotti@arm.com
Wed Oct 8 10:34:42 GMT 2025


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.

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