aarch64: Support for FEAT_CMPBR

Message ID 20250407135714.39245-1-Ezra.Sitorus@arm.com
State New
Headers
Series aarch64: Support for FEAT_CMPBR |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 fail Build failed
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_binutils_check--master-arm success Test passed

Commit Message

Ezra Sitorus April 7, 2025, 1:57 p.m. UTC
  From: Ezra Sitorus <ezra.sitorus@arm.com>

FEAT_CMPBR - Compare and branch instructions. This patch adds these
instructions:
- CB<CC> (register)
- CB<CC> (immediate)
- CBH<CC>
- CBB<CC>

where CC is one of the following:
- EQ
- NE
- GT
- GE
- LT
- LE
- HI
- HS
- LO
- LS

Some instructions are pseudo-instructions: cbgt w0, w1, <label> is the
same as cblt w1, w0, <label>. No new relocation type for the 9 bit offset has
been introduced to the AArch64 ELF ABI.

Details of the instructions can be found here:
https://developer.arm.com/documentation/109697/2024_12/Feature-descriptions/The-Armv9-6-architecture-extension
https://developer.arm.com/documentation/ddi0602/2024-12/Base-Instructions/CB-cc---register---Compare-registers-and-branch-?lang=en
https://developer.arm.com/documentation/ddi0602/2024-12/Base-Instructions/CB-cc---immediate---Compare-register-with-immediate-and-branch-?lang=en
https://developer.arm.com/documentation/ddi0602/2024-12/Base-Instructions/CBB-cc---Compare-bytes-and-branch-?lang=en
https://developer.arm.com/documentation/ddi0602/2024-12/Base-Instructions/CBH-cc---Compare-halfwords-and-branch-?lang=en
---

If this looks ok, could somebody commit this? I don't have commit rights.

 bfd/elfnn-aarch64.c                   |  3 ++
 bfd/reloc.c                           |  8 +++-
 gas/config/tc-aarch64.c               | 40 +++++++++++++++-
 gas/testsuite/gas/aarch64/cmpbr-1.d   | 66 +++++++++++++++++++++++++++
 gas/testsuite/gas/aarch64/cmpbr-1.s   | 59 ++++++++++++++++++++++++
 gas/testsuite/gas/aarch64/cmpbr-bad.d |  3 ++
 gas/testsuite/gas/aarch64/cmpbr-bad.l | 13 ++++++
 gas/testsuite/gas/aarch64/cmpbr-bad.s |  5 ++
 gas/testsuite/gas/aarch64/cmpbr.d     | 54 ++++++++++++++++++++++
 gas/testsuite/gas/aarch64/cmpbr.s     | 47 +++++++++++++++++++
 include/opcode/aarch64.h              |  3 ++
 opcodes/aarch64-opc.c                 |  3 ++
 opcodes/aarch64-opc.h                 |  1 +
 opcodes/aarch64-tbl.h                 | 61 +++++++++++++++++++++++++
 14 files changed, 363 insertions(+), 3 deletions(-)
 create mode 100644 gas/testsuite/gas/aarch64/cmpbr-1.d
 create mode 100644 gas/testsuite/gas/aarch64/cmpbr-1.s
 create mode 100644 gas/testsuite/gas/aarch64/cmpbr-bad.d
 create mode 100644 gas/testsuite/gas/aarch64/cmpbr-bad.l
 create mode 100644 gas/testsuite/gas/aarch64/cmpbr-bad.s
 create mode 100644 gas/testsuite/gas/aarch64/cmpbr.d
 create mode 100644 gas/testsuite/gas/aarch64/cmpbr.s
  

Comments

Richard Earnshaw April 8, 2025, 10:45 a.m. UTC | #1
On 07/04/2025 14:57, Ezra.Sitorus@arm.com wrote:
> From: Ezra Sitorus <ezra.sitorus@arm.com>
> 
> FEAT_CMPBR - Compare and branch instructions. This patch adds these
> instructions:
> - CB<CC> (register)
> - CB<CC> (immediate)
> - CBH<CC>
> - CBB<CC>
> 
> where CC is one of the following:
> - EQ
> - NE
> - GT
> - GE
> - LT
> - LE
> - HI
> - HS
> - LO
> - LS
> 
> Some instructions are pseudo-instructions: cbgt w0, w1, <label> is the
> same as cblt w1, w0, <label>. No new relocation type for the 9 bit offset has
> been introduced to the AArch64 ELF ABI.
> 
> Details of the instructions can be found here:
> https://developer.arm.com/documentation/109697/2024_12/Feature-descriptions/The-Armv9-6-architecture-extension
> https://developer.arm.com/documentation/ddi0602/2024-12/Base-Instructions/CB-cc---register---Compare-registers-and-branch-?lang=en
> https://developer.arm.com/documentation/ddi0602/2024-12/Base-Instructions/CB-cc---immediate---Compare-register-with-immediate-and-branch-?lang=en
> https://developer.arm.com/documentation/ddi0602/2024-12/Base-Instructions/CBB-cc---Compare-bytes-and-branch-?lang=en
> https://developer.arm.com/documentation/ddi0602/2024-12/Base-Instructions/CBH-cc---Compare-halfwords-and-branch-?lang=en
> ---
> 
> If this looks ok, could somebody commit this? I don't have commit rights.
> 
>   bfd/elfnn-aarch64.c                   |  3 ++
>   bfd/reloc.c                           |  8 +++-
>   gas/config/tc-aarch64.c               | 40 +++++++++++++++-
>   gas/testsuite/gas/aarch64/cmpbr-1.d   | 66 +++++++++++++++++++++++++++
>   gas/testsuite/gas/aarch64/cmpbr-1.s   | 59 ++++++++++++++++++++++++
>   gas/testsuite/gas/aarch64/cmpbr-bad.d |  3 ++
>   gas/testsuite/gas/aarch64/cmpbr-bad.l | 13 ++++++
>   gas/testsuite/gas/aarch64/cmpbr-bad.s |  5 ++
>   gas/testsuite/gas/aarch64/cmpbr.d     | 54 ++++++++++++++++++++++
>   gas/testsuite/gas/aarch64/cmpbr.s     | 47 +++++++++++++++++++
>   include/opcode/aarch64.h              |  3 ++
>   opcodes/aarch64-opc.c                 |  3 ++
>   opcodes/aarch64-opc.h                 |  1 +
>   opcodes/aarch64-tbl.h                 | 61 +++++++++++++++++++++++++
>   14 files changed, 363 insertions(+), 3 deletions(-)
>   create mode 100644 gas/testsuite/gas/aarch64/cmpbr-1.d
>   create mode 100644 gas/testsuite/gas/aarch64/cmpbr-1.s
>   create mode 100644 gas/testsuite/gas/aarch64/cmpbr-bad.d
>   create mode 100644 gas/testsuite/gas/aarch64/cmpbr-bad.l
>   create mode 100644 gas/testsuite/gas/aarch64/cmpbr-bad.s
>   create mode 100644 gas/testsuite/gas/aarch64/cmpbr.d
>   create mode 100644 gas/testsuite/gas/aarch64/cmpbr.s
> 
> diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
> index 548da1f8b30..8f399204f04 100644
> --- a/bfd/elfnn-aarch64.c
> +++ b/bfd/elfnn-aarch64.c
> @@ -2268,6 +2268,9 @@ elfNN_aarch64_howto_from_bfd_reloc (bfd_reloc_code_real_type code)
>     if (code == BFD_RELOC_AARCH64_NONE)
>       return &elfNN_aarch64_howto_none;
>   
> +  if (code == BFD_RELOC_AARCH64_BRANCH9)
> +    return &elfNN_aarch64_howto_none;
> +
>     return NULL;
>   }
>   
> diff --git a/bfd/reloc.c b/bfd/reloc.c
> index d3ddafb7305..4182330d0bb 100644
> --- a/bfd/reloc.c
> +++ b/bfd/reloc.c
> @@ -7202,7 +7202,7 @@ ENUM
>     BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC
>   ENUMDOC
>     Similar to BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12, but no
> -  overflow check.
> +  overflow check.
>   ENUM
>     BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12
>   ENUMDOC
> @@ -7418,6 +7418,12 @@ ENUM
>   ENUMDOC
>     AArch64 pseudo relocation code to be used internally by the AArch64
>     assembler and not (currently) written to any object files.
> +ENUM
> +  BFD_RELOC_AARCH64_BRANCH9
> +ENUMDOC
> +	AArch64 9 bit pc-relative conditional branch and compare & branch.
> +	The lowest two bits must be zero and are not stored in the
> +	instruction, giving an 11 bit signed byte offset.

There appear to be a lot of indentation issues in this patch.  The above 
is just the first.  The text here should be indented by the same amount 
as the other ENUMDOC entries (eg immediately above).

>   ENUM
>     BFD_RELOC_TILEPRO_COPY
>   ENUMX
> diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
> index e071ad11f46..c34eb301b42 100644
> --- a/gas/config/tc-aarch64.c
> +++ b/gas/config/tc-aarch64.c
> @@ -5175,6 +5175,13 @@ encode_branch_ofs_26 (uint32_t ofs)
>     return ofs & ((1 << 26) - 1);
>   }
>   
> +/* encode the 9-bit offset of FEAT_CMPBR compare and branch */
> +static inline uint32_t
> +encode_cond_branch_ofs_9 (uint32_t ofs)
> +{
> +  return (ofs & ((1 << 9) - 1)) << 5;
> +}
> +
>   /* encode the 19-bit offset of conditional branch and compare & branch */
>   static inline uint32_t
>   encode_cond_branch_ofs_19 (uint32_t ofs)
> @@ -6388,6 +6395,8 @@ process_omitted_operand (enum aarch64_opnd type, const aarch64_opcode *opcode,
>       case AARCH64_OPND_UIMM3_OP2:
>       case AARCH64_OPND_IMM:
>       case AARCH64_OPND_IMM_2:
> +    case AARCH64_OPND_IMMP1_2:
> +    case AARCH64_OPND_IMMS1_2:
>       case AARCH64_OPND_WIDTH:
>       case AARCH64_OPND_UIMM7:
>       case AARCH64_OPND_NZCV:
> @@ -7154,6 +7163,16 @@ parse_operands (char *str, const aarch64_opcode *opcode)
>   	  info->imm.value = val;
>   	  break;
>   
> +	case AARCH64_OPND_IMMP1_2:
> +	  po_imm_nc_or_fail ();
> +		info->imm.value = val - 1;
> +		break;

Indentation.

> +
> +	case AARCH64_OPND_IMMS1_2:
> +	  po_imm_nc_or_fail ();
> +		info->imm.value = val + 1;
> +		break;
And again.

> +
>   	case AARCH64_OPND_SVE_AIMM:
>   	case AARCH64_OPND_SVE_ASIMM:
>   	  po_imm_nc_or_fail ();
> @@ -7450,6 +7469,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
>   	  info->imm.value = 0;
>   	  break;
>   
> +	case AARCH64_OPND_ADDR_PCREL9:
>   	case AARCH64_OPND_ADDR_PCREL14:
>   	case AARCH64_OPND_ADDR_PCREL19:
>   	case AARCH64_OPND_ADDR_PCREL21:
> @@ -7487,8 +7507,10 @@ parse_operands (char *str, const aarch64_opcode *opcode)
>   		  case compbranch:
>   		  case condbranch:
>   		    /* e.g. CBZ or B.COND  */
> -		    gas_assert (operands[i] == AARCH64_OPND_ADDR_PCREL19);
> -		    inst.reloc.type = BFD_RELOC_AARCH64_BRANCH19;
> +		    gas_assert (operands[i] == AARCH64_OPND_ADDR_PCREL9 ||
The '||' should be on the continuation line, not at the end of the 
preceding one.  It should be indented to be one character beyond the 
nesting brace).

> +							operands[i] == AARCH64_OPND_ADDR_PCREL19);
> +		    inst.reloc.type = operands[i] == AARCH64_OPND_ADDR_PCREL9 ?

Similarly for the '?'.  In this case add parenthesis so that the entire 
expression is indened cleanly...

   a = (op == xx
        ? YYY
        : ZZZ);

> +							BFD_RELOC_AARCH64_BRANCH9 : BFD_RELOC_AARCH64_BRANCH19;
>   		    break;
>   		  case testbranch:
>   		    /* e.g. TBZ  */
> @@ -9670,6 +9692,20 @@ md_apply_fix (fixS * fixP, valueT * valP, segT seg)
>   	}
>         break;
>   
> +    case BFD_RELOC_AARCH64_BRANCH9:
> +        if (fixP->fx_done || !seg->use_rela_p)

Indentation is wrong here as well.

> +	{
> +	  if (value & 3)
> +	    as_bad_where (fixP->fx_file, fixP->fx_line,
> +			  _("conditional branch target not word aligned"));
> +	  if (signed_overflow (value, 11))
> +	    as_bad_where (fixP->fx_file, fixP->fx_line,
> +			  _("conditional branch out of range"));
> +	  insn = get_aarch64_insn (buf);
> +	  insn |= encode_cond_branch_ofs_9 (value >> 2);
> +	  put_aarch64_insn (buf, insn);
> +	}
> +        break;
>       case BFD_RELOC_AARCH64_BRANCH19:
>         if (fixP->fx_done || !seg->use_rela_p)
>   	{
> diff --git a/gas/testsuite/gas/aarch64/cmpbr-1.d b/gas/testsuite/gas/aarch64/cmpbr-1.d
> new file mode 100644
> index 00000000000..02a5aa07066
> --- /dev/null
> +++ b/gas/testsuite/gas/aarch64/cmpbr-1.d
> @@ -0,0 +1,66 @@
> +#name: Test for FEAT_CMPBR pseudo-instructions
> +#objdump: -dr
> +
> +.*:     file format .*
> +
> +Disassembly of section .text:
> +
> +0000000000000000 <a>:
> +   0:	74010000 	cbgt	w0, w1, 0 <a>
> +   4:	74013fe0 	cbgt	w0, w1, 0 <a>
> +   8:	74213fc0 	cbge	w0, w1, 0 <a>
> +   c:	74213fa0 	cbge	w0, w1, 0 <a>
> +  10:	74413f80 	cbhi	w0, w1, 0 <a>
> +  14:	74413f60 	cbhi	w0, w1, 0 <a>
> +  18:	74613f40 	cbhs	w0, w1, 0 <a>
> +  1c:	74613f20 	cbhs	w0, w1, 0 <a>

We normally replace the addresses with wild-card patterns so that there 
is less churn on the tests if new instructions are inserted.

> +
> +0000000000000020 <b>:
> +  20:	f4010000 	cbgt	x0, x1, 20 <b>
> +  24:	f4013fe0 	cbgt	x0, x1, 20 <b>
> +  28:	f4213fc0 	cbge	x0, x1, 20 <b>
> +  2c:	f4213fa0 	cbge	x0, x1, 20 <b>
> +  30:	f4413f80 	cbhi	x0, x1, 20 <b>
> +  34:	f4413f60 	cbhi	x0, x1, 20 <b>
> +  38:	f4613f40 	cbhs	x0, x1, 20 <b>
> +  3c:	f4613f20 	cbhs	x0, x1, 20 <b>
> +
> +0000000000000040 <c>:
> +  40:	75050000 	cbgt	w0, #10, 40 <c>
> +  44:	75053fe0 	cbgt	w0, #10, 40 <c>
> +  48:	75263fc0 	cblt	w0, #12, 40 <c>
> +  4c:	75263fa1 	cblt	w1, #12, 40 <c>
> +  50:	75453f80 	cbhi	w0, #10, 40 <c>
> +  54:	75453f60 	cbhi	w0, #10, 40 <c>
> +  58:	75663f41 	cblo	w1, #12, 40 <c>
> +  5c:	7566bf21 	cblo	w1, #13, 40 <c>
> +
> +0000000000000060 <d>:
> +  60:	f5050000 	cbgt	x0, #10, 60 <d>
> +  64:	f5053fe0 	cbgt	x0, #10, 60 <d>
> +  68:	f5263fc0 	cblt	x0, #12, 60 <d>
> +  6c:	f5263fa1 	cblt	x1, #12, 60 <d>
> +  70:	f5453f80 	cbhi	x0, #10, 60 <d>
> +  74:	f5453f60 	cbhi	x0, #10, 60 <d>
> +  78:	f5663f41 	cblo	x1, #12, 60 <d>
> +  7c:	f566bf21 	cblo	x1, #13, 60 <d>
> +
> +0000000000000080 <e>:
> +  80:	74018000 	cbbgt	w0, w1, 80 <e>
> +  84:	7401bfe0 	cbbgt	w0, w1, 80 <e>
> +  88:	7421bfc0 	cbbge	w0, w1, 80 <e>
> +  8c:	7421bfa0 	cbbge	w0, w1, 80 <e>
> +  90:	7441bf80 	cbbhi	w0, w1, 80 <e>
> +  94:	7441bf60 	cbbhi	w0, w1, 80 <e>
> +  98:	7461bf40 	cbbhs	w0, w1, 80 <e>
> +  9c:	7461bf20 	cbbhs	w0, w1, 80 <e>
> +
> +00000000000000a0 <f>:
> +  a0:	7401c000 	cbhgt	w0, w1, a0 <f>
> +  a4:	7401ffe0 	cbhgt	w0, w1, a0 <f>
> +  a8:	7421ffc0 	cbhge	w0, w1, a0 <f>
> +  ac:	7421ffa0 	cbhge	w0, w1, a0 <f>
> +  b0:	7441ff80 	cbhhi	w0, w1, a0 <f>
> +  b4:	7440ff61 	cbhhi	w1, w0, a0 <f>
> +  b8:	7461ff40 	cbhhs	w0, w1, a0 <f>
> +  bc:	7461ff20 	cbhhs	w0, w1, a0 <f>
> diff --git a/gas/testsuite/gas/aarch64/cmpbr-1.s b/gas/testsuite/gas/aarch64/cmpbr-1.s
> new file mode 100644
> index 00000000000..0d17ebb03c9
> --- /dev/null
> +++ b/gas/testsuite/gas/aarch64/cmpbr-1.s
> @@ -0,0 +1,59 @@
> +a:
> +    cbgt w0, w1, a

The preferred style for assembler source is
<tab><mnemonic><tab><operands>
So
	cbgt	w0, r1, a
Tabs are standard hard tabs (8 columns).

> +    cblt w1, w0, a
> +    cbge w0, w1, a
> +    cble w1, w0, a
> +    cbhi w0, w1, a
> +    cblo w1, w0, a
> +    cbhs w0, w1, a
> +    cbls w1, w0, a
> +
> +b:
> +    cbgt x0, x1, b
> +    cblt x1, x0, b
> +    cbge x0, x1, b
> +    cble x1, x0, b
> +    cbhi x0, x1, b
> +    cblo x1, x0, b
> +    cbhs x0, x1, b
> +    cbls x1, x0, b
> +
> +c:
> +    cbgt w0, #10, c
> +    cbge w0, #11, c
> +    cblt w0, #12, c
> +    cble w1, #11, c
> +    cbhi w0, #10, c
> +    cbhs w0, #11, c
> +    cblo w1, #12, c
> +    cbls w1, #12, c
> +
> +d:
> +    cbgt x0, #10, d
> +    cbge x0, #11, d
> +    cblt x0, #12, d
> +    cble x1, #11, d
> +    cbhi x0, #10, d
> +    cbhs x0, #11, d
> +    cblo x1, #12, d
> +    cbls x1, #12, d
> +
> +e:
> +    cbbgt w0, w1, e
> +    cbblt w1, w0, e
> +    cbbge w0, w1, e
> +    cbble w1, w0, e
> +    cbbhi w0, w1, e
> +    cbblo w1, w0, e
> +    cbbhs w0, w1, e
> +    cbbls w1, w0, e
> +
> +f:
> +    cbhgt w0, w1, f
> +    cbhlt w1, w0, f
> +    cbhge w0, w1, f
> +    cbhle w1, w0, f
> +    cbhhi w0, w1, f
> +    cbhlo w1, w0, f
> +    cbhhs w0, w1, f
> +    cbhls w1, w0, f
> diff --git a/gas/testsuite/gas/aarch64/cmpbr-bad.d b/gas/testsuite/gas/aarch64/cmpbr-bad.d
> new file mode 100644
> index 00000000000..802d39e7294
> --- /dev/null
> +++ b/gas/testsuite/gas/aarch64/cmpbr-bad.d
> @@ -0,0 +1,3 @@
> +#name: Test of invalid cmpbr operands
> +#source: cmpbr-bad.s
> +#error_output: cmpbr-bad.l
> diff --git a/gas/testsuite/gas/aarch64/cmpbr-bad.l b/gas/testsuite/gas/aarch64/cmpbr-bad.l
> new file mode 100644
> index 00000000000..f705cfd0043
> --- /dev/null
> +++ b/gas/testsuite/gas/aarch64/cmpbr-bad.l
> @@ -0,0 +1,13 @@
> +.[^ :]+: Assembler messages:
> +[^ :]+:[0-9]+: Error: operand mismatch -- `cbgt w0,x1,a'
> +[^ :]+:[0-9]+: Info:    did you mean this\?
> +[^ :]+:[0-9]+: Info:    	cbgt w0, w1, #0x0
> +[^ :]+:[0-9]+: Info:    other valid variant\(s\):
> +[^ :]+:[0-9]+: Info:    	cbgt x0, x1, #0x0
> +[^ :]+:[0-9]+: Error: immediate value out of range 0 to 63 at operand 2 -- `cbgt w0,#64,a'
> +[^ :]+:[0-9]+: Error: operand mismatch -- `cbbgt x0,x1,a'
> +[^ :]+:[0-9]+: Info:    did you mean this\?
> +[^ :]+:[0-9]+: Info:    	cbbgt w0, w1, #0x0
> +[^ :]+:[0-9]+: Error: operand mismatch -- `cbhgt x0,x1,a'
> +[^ :]+:[0-9]+: Info:    did you mean this\?
> +[^ :]+:[0-9]+: Info:    	cbhgt w0, w1, #0x0
> diff --git a/gas/testsuite/gas/aarch64/cmpbr-bad.s b/gas/testsuite/gas/aarch64/cmpbr-bad.s
> new file mode 100644
> index 00000000000..80b31b827dc
> --- /dev/null
> +++ b/gas/testsuite/gas/aarch64/cmpbr-bad.s
> @@ -0,0 +1,5 @@
> +a:
> +    cbgt w0, x1, a
> +    cbgt w0, #64, a
> +    cbbgt x0, x1, a
> +    cbhgt x0, x1, a
> diff --git a/gas/testsuite/gas/aarch64/cmpbr.d b/gas/testsuite/gas/aarch64/cmpbr.d
> new file mode 100644
> index 00000000000..1ee2d3a0f5d
> --- /dev/null
> +++ b/gas/testsuite/gas/aarch64/cmpbr.d
> @@ -0,0 +1,54 @@
> +#name: Test for FEAT_CMPBR
> +#objdump: -dr
> +
> +.*:     file format .*
> +
> +Disassembly of section .text:
> +
> +0000000000000000 <a>:
> +   0:	74010000 	cbgt	w0, w1, 0 <a>
> +   4:	74213fe0 	cbge	w0, w1, 0 <a>
> +   8:	74413fc0 	cbhi	w0, w1, 0 <a>
> +   c:	74613fa0 	cbhs	w0, w1, 0 <a>
> +  10:	74c13f80 	cbeq	w0, w1, 0 <a>
> +  14:	74e13f60 	cbne	w0, w1, 0 <a>
> +
> +0000000000000018 <b>:
> +  18:	f4010000 	cbgt	x0, x1, 18 <b>
> +  1c:	f4213fe0 	cbge	x0, x1, 18 <b>
> +  20:	f4413fc0 	cbhi	x0, x1, 18 <b>
> +  24:	f4613fa0 	cbhs	x0, x1, 18 <b>
> +  28:	f4c13f80 	cbeq	x0, x1, 18 <b>
> +  2c:	f4e13f60 	cbne	x0, x1, 18 <b>
> +
> +0000000000000030 <c>:
> +  30:	75010000 	cbgt	w0, #2, 30 <c>
> +  34:	75223fe0 	cblt	w0, #4, 30 <c>
> +  38:	75433fc0 	cbhi	w0, #6, 30 <c>
> +  3c:	75643fa0 	cblo	w0, #8, 30 <c>
> +  40:	75c53f80 	cbeq	w0, #10, 30 <c>
> +  44:	75e63f60 	cbne	w0, #12, 30 <c>
> +
> +0000000000000048 <d>:
> +  48:	f5070000 	cbgt	x0, #14, 48 <d>
> +  4c:	f5283fe0 	cblt	x0, #16, 48 <d>
> +  50:	f5493fc0 	cbhi	x0, #18, 48 <d>
> +  54:	f56a3fa0 	cblo	x0, #20, 48 <d>
> +  58:	f5cb3f80 	cbeq	x0, #22, 48 <d>
> +  5c:	f5ec3f60 	cbne	x0, #24, 48 <d>
> +
> +0000000000000060 <e>:
> +  60:	74018000 	cbbgt	w0, w1, 60 <e>
> +  64:	7421bfe0 	cbbge	w0, w1, 60 <e>
> +  68:	7441bfc0 	cbbhi	w0, w1, 60 <e>
> +  6c:	7461bfa0 	cbbhs	w0, w1, 60 <e>
> +  70:	74c1bf80 	cbbeq	w0, w1, 60 <e>
> +  74:	74e1bf60 	cbbne	w0, w1, 60 <e>
> +
> +0000000000000078 <f>:
> +  78:	7401c000 	cbhgt	w0, w1, 78 <f>
> +  7c:	7421ffe0 	cbhge	w0, w1, 78 <f>
> +  80:	7441ffc0 	cbhhi	w0, w1, 78 <f>
> +  84:	7461ffa0 	cbhhs	w0, w1, 78 <f>
> +  88:	74c1ff80 	cbheq	w0, w1, 78 <f>
> +  8c:	74e1ff60 	cbhne	w0, w1, 78 <f>
> diff --git a/gas/testsuite/gas/aarch64/cmpbr.s b/gas/testsuite/gas/aarch64/cmpbr.s
> new file mode 100644
> index 00000000000..a259dc8018d
> --- /dev/null
> +++ b/gas/testsuite/gas/aarch64/cmpbr.s
> @@ -0,0 +1,47 @@
> +a:
> +    cbgt w0, w1, a
> +    cbge w0, w1, a
> +    cbhi w0, w1, a
> +    cbhs w0, w1, a
> +    cbeq w0, w1, a
> +    cbne w0, w1, a
> +
> +b:
> +    cbgt x0, x1, b
> +    cbge x0, x1, b
> +    cbhi x0, x1, b
> +    cbhs x0, x1, b
> +    cbeq x0, x1, b
> +    cbne x0, x1, b
> +
> +c:
> +    cbgt w0, #2, c
> +    cblt w0, #4, c
> +    cbhi w0, #6, c
> +    cblo w0, #8, c
> +    cbeq w0, #10, c
> +    cbne w0, #12, c
> +
> +d:
> +    cbgt x0, #14, d
> +    cblt x0, #16, d
> +    cbhi x0, #18, d
> +    cblo x0, #20, d
> +    cbeq x0, #22, d
> +    cbne x0, #24, d
> +
> +e:
> +    cbbgt w0, w1, e
> +    cbbge w0, w1, e
> +    cbbhi w0, w1, e
> +    cbbhs w0, w1, e
> +    cbbeq w0, w1, e
> +    cbbne w0, w1, e
> +
> +f:
> +    cbhgt w0, w1, f
> +    cbhge w0, w1, f
> +    cbhhi w0, w1, f
> +    cbhhs w0, w1, f
> +    cbheq w0, w1, f
> +    cbhne w0, w1, f
> diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h
> index dfe3f05820a..b6da2d962e6 100644
> --- a/include/opcode/aarch64.h
> +++ b/include/opcode/aarch64.h
> @@ -618,6 +618,8 @@ enum aarch64_opnd
>     AARCH64_OPND_WIDTH,	/* Immediate #<width> in e.g. BFI.  */
>     AARCH64_OPND_IMM,	/* Immediate.  */
>     AARCH64_OPND_IMM_2,	/* Immediate.  */
> +  AARCH64_OPND_IMMP1_2,	/* Immediate plus 1.  */
> +  AARCH64_OPND_IMMS1_2,	/* Immediate minus 1.  */

Indentaion

>     AARCH64_OPND_UIMM3_OP1,/* Unsigned 3-bit immediate in the op1 field.  */
>     AARCH64_OPND_UIMM3_OP2,/* Unsigned 3-bit immediate in the op2 field.  */
>     AARCH64_OPND_UIMM4,	/* Unsigned 4-bit immediate in the CRm field.  */
> @@ -645,6 +647,7 @@ enum aarch64_opnd
>     AARCH64_OPND_COND1,	/* Same as the above, but excluding AL and NV.  */
>   
>     AARCH64_OPND_ADDR_ADRP,	/* Memory address for ADRP */
> +  AARCH64_OPND_ADDR_PCREL9,	/* 9-bit PC-relative address for e.g. CB<cc>.  */

And again

>     AARCH64_OPND_ADDR_PCREL14,	/* 14-bit PC-relative address for e.g. TBZ.  */
>     AARCH64_OPND_ADDR_PCREL19,	/* 19-bit PC-relative address for e.g. LDR.  */
>     AARCH64_OPND_ADDR_PCREL21,	/* 21-bit PC-relative address for e.g. ADR.  */
> diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
> index 4f0c71696fa..e4dc58f439a 100644
> --- a/opcodes/aarch64-opc.c
> +++ b/opcodes/aarch64-opc.c
> @@ -381,6 +381,7 @@ const aarch64_field fields[] =
>       { 15,  7 },	/* imm7: in load/store pair pre/post index instructions.  */
>       { 13,  8 },	/* imm8: in floating-point scalar move immediate inst.  */
>       { 12,  9 },	/* imm9: in load/store pre/post index instructions.  */
> +    { 5,   9 },	/* imm9_5: in CB<cc> (immediate).  */

and again (there are more below, please check them all).

>       { 10, 12 },	/* imm12: in ld/st unsigned imm or add/sub shifted inst.  */
>       {  5, 14 },	/* imm14: in test bit and branch instructions.  */
>       {  0, 16 },	/* imm16_0: in udf instruction. */
> @@ -2417,6 +2418,7 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
>   	    }
>   	  break;
>   
> +	case AARCH64_OPND_ADDR_PCREL9:
>   	case AARCH64_OPND_ADDR_PCREL14:
>   	case AARCH64_OPND_ADDR_PCREL19:
>   	case AARCH64_OPND_ADDR_PCREL21:
> @@ -4781,6 +4783,7 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
>         snprintf (buf, size, "%s", style_addr (styler, "#0x%" PRIx64 , addr));
>         break;
>   
> +    case AARCH64_OPND_ADDR_PCREL9:
>       case AARCH64_OPND_ADDR_PCREL14:
>       case AARCH64_OPND_ADDR_PCREL19:
>       case AARCH64_OPND_ADDR_PCREL21:
> diff --git a/opcodes/aarch64-opc.h b/opcodes/aarch64-opc.h
> index 9ab9bdf5123..3086f0285d8 100644
> --- a/opcodes/aarch64-opc.h
> +++ b/opcodes/aarch64-opc.h
> @@ -185,6 +185,7 @@ enum aarch64_field_kind
>     FLD_imm7,
>     FLD_imm8,
>     FLD_imm9,
> +  FLD_imm9_5,
>     FLD_imm12,
>     FLD_imm14,
>     FLD_imm16_0,
> diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h
> index 8b64eb07067..bb560139d1e 100644
> --- a/opcodes/aarch64-tbl.h
> +++ b/opcodes/aarch64-tbl.h
> @@ -136,6 +136,19 @@
>     QLF2(X,NIL),			\
>   }
>   
> +/* e.g. CBBGT <Wt>, <Wm>, <label>.  */
> +#define QL_W2_PCREL		\
> +{				\
> +  QLF3(W,W,NIL),		\
> +}
> +
> +/* e.g. CBGT <Wt>, #<imm6>, <label>.  */
> +#define QL_R_IMM_PCREL		\
> +{				\
> +  QLF3(W,imm_0_63,NIL),		\
> +  QLF3(X,imm_0_63,NIL),		\
> +}
> +
>   /* e.g. LDR <Dt>, <label>.  */
>   #define QL_FP_PCREL		\
>   {				\
> @@ -3965,6 +3978,50 @@ const struct aarch64_opcode aarch64_opcode_table[] =
>     CORE_INSN ("cbnz", 0x35000000, 0x7f000000, compbranch, 0, OP2 (Rt, ADDR_PCREL19), QL_R_PCREL, F_SF),
>     /* Conditional branch (immediate).  */
>     CORE_INSN ("b.c", 0x54000000, 0xff000010, condbranch, 0, OP1 (ADDR_PCREL19), QL_PCREL_NIL, F_COND),
> +  /* Compare registers and branch. */
> +  CORE_INSN ("cbgt", 0x74000000, 0x7fe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF | F_ALIAS),
> +  CORE_INSN ("cblt", 0x74000000, 0x7fe0c000, compbranch, 0, OP3 (Rm, Rt, ADDR_PCREL9), QL_R2NIL, F_SF | F_HAS_ALIAS),
> +  CORE_INSN ("cbge", 0x74200000, 0x7fe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF | F_ALIAS),
> +  CORE_INSN ("cble", 0x74200000, 0x7fe0c000, compbranch, 0, OP3 (Rm, Rt, ADDR_PCREL9), QL_R2NIL, F_SF | F_HAS_ALIAS),
> +  CORE_INSN ("cbhi", 0x74400000, 0x7fe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF | F_ALIAS),
> +  CORE_INSN ("cblo", 0x74400000, 0x7fe0c000, compbranch, 0, OP3 (Rm, Rt, ADDR_PCREL9), QL_R2NIL, F_SF | F_HAS_ALIAS),
> +  CORE_INSN ("cbhs", 0x74600000, 0x7fe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF | F_ALIAS),
> +  CORE_INSN ("cbls", 0x74600000, 0x7fe0c000, compbranch, 0, OP3 (Rm, Rt, ADDR_PCREL9), QL_R2NIL, F_SF | F_HAS_ALIAS),
> +  CORE_INSN ("cbeq", 0x74c00000, 0x7fe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF),
> +  CORE_INSN ("cbne", 0x74e00000, 0x7fe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF),
> +  /* Compare register with immediate and branch.  */
> +  CORE_INSN ("cbgt", 0x75000000, 0x7fe04000, compbranch, 0, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_ALIAS),
> +  CORE_INSN ("cbge", 0x75000000, 0x7fe04000, compbranch, 0, OP3 (Rt, IMMP1_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_HAS_ALIAS),
> +  CORE_INSN ("cblt", 0x75200000, 0x7fe04000, compbranch, 0, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_ALIAS),
> +  CORE_INSN ("cble", 0x75200000, 0x7fe04000, compbranch, 0, OP3 (Rt, IMMS1_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_HAS_ALIAS),
> +  CORE_INSN ("cbhi", 0x75400000, 0x7fe04000, compbranch, 0, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_ALIAS),
> +  CORE_INSN ("cbhs", 0x75400000, 0x7fe04000, compbranch, 0, OP3 (Rt, IMMP1_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_HAS_ALIAS),
> +  CORE_INSN ("cblo", 0x75600000, 0x7fe04000, compbranch, 0, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_ALIAS),
> +  CORE_INSN ("cbls", 0x75600000, 0x7fe04000, compbranch, 0, OP3 (Rt, IMMS1_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_HAS_ALIAS),
> +  CORE_INSN ("cbeq", 0x75c00000, 0x7fe04000, compbranch, 0, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF),
> +  CORE_INSN ("cbne", 0x75e00000, 0x7fe04000, compbranch, 0, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF),
> +  // /* Compare bytes and branch.  */

We don't use C++ style // comments in binutils.

> +  CORE_INSN ("cbbgt", 0x74008000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS),
> +  CORE_INSN ("cbblt", 0x74008000, 0xffe0c000, compbranch, 0, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
> +  CORE_INSN ("cbbge", 0x74208000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS),
> +  CORE_INSN ("cbble", 0x74208000, 0xffe0c000, compbranch, 0, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
> +  CORE_INSN ("cbbhi", 0x74408000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS),
> +  CORE_INSN ("cbblo", 0x74408000, 0xffe0c000, compbranch, 0, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
> +  CORE_INSN ("cbbhs", 0x74608000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS),
> +  CORE_INSN ("cbbls", 0x74608000, 0xffe0c000, compbranch, 0, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
> +  CORE_INSN ("cbbeq", 0x74c08000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, 0),
> +  CORE_INSN ("cbbne", 0x74e08000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, 0),
> +  // /* Compare halfwords and branch.  */
And here.

> +  CORE_INSN ("cbhgt", 0x7400c000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS),
> +  CORE_INSN ("cbhlt", 0x7400c000, 0xffe0c000, compbranch, 0, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
> +  CORE_INSN ("cbhge", 0x7420c000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS),
> +  CORE_INSN ("cbhle", 0x7420c000, 0xffe0c000, compbranch, 0, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
> +  CORE_INSN ("cbhhi", 0x7440c000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS),
> +  CORE_INSN ("cbhlo", 0x7440c000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
> +  CORE_INSN ("cbhhs", 0x7460c000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS),
> +  CORE_INSN ("cbhls", 0x7460c000, 0xffe0c000, compbranch, 0, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
> +  CORE_INSN ("cbheq", 0x74c0c000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, 0),
> +  CORE_INSN ("cbhne", 0x74e0c000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, 0),
>     /* Conditional compare (immediate).  */
>     CORE_INSN ("ccmn", 0x3a400800, 0x7fe00c10, condcmp_imm, 0, OP4 (Rn, CCMP_IMM, NZCV, COND), QL_CCMP_IMM, F_SF),
>     CORE_INSN ("ccmp", 0x7a400800, 0x7fe00c10, condcmp_imm, 0, OP4 (Rn, CCMP_IMM, NZCV, COND), QL_CCMP_IMM, F_SF),
> @@ -7126,6 +7183,8 @@ const struct aarch64_opcode aarch64_opcode_table[] =
>         "the width of the bit-field")					\
>       Y(IMMEDIATE, imm, "IMM", 0, F(FLD_imm6_10), "an immediate")         \
>       Y(IMMEDIATE, imm, "IMM_2", 0, F(FLD_imm6_15), "an immediate")       \
> +    Y(IMMEDIATE, imm, "IMMP1_2", 0, F(FLD_imm6_15), "an immediate plus 1")       \
> +    Y(IMMEDIATE, imm, "IMMS1_2", 0, F(FLD_imm6_15), "an immediate minus 1")       \
>       Y(IMMEDIATE, imm, "UIMM3_OP1", 0, F(FLD_op1),			\
>         "a 3-bit unsigned immediate")					\
>       Y(IMMEDIATE, imm, "UIMM3_OP2", 0, F(FLD_op2),			\
> @@ -7170,6 +7229,8 @@ const struct aarch64_opcode aarch64_opcode_table[] =
>         "one of the standard conditions, excluding AL and NV.")		\
>       X(ADDRESS, 0, ext_imm, "ADDR_ADRP", OPD_F_SEXT, F(FLD_immhi, FLD_immlo),\
>         "21-bit PC-relative address of a 4KB page")			\
> +    Y(ADDRESS, imm, "ADDR_PCREL9", OPD_F_SEXT | OPD_F_SHIFT_BY_2,	\
> +      F(FLD_imm9_5), "9-bit PC-relative address")			\
>       Y(ADDRESS, imm, "ADDR_PCREL14", OPD_F_SEXT | OPD_F_SHIFT_BY_2,	\
>         F(FLD_imm14), "14-bit PC-relative address")			\
>       Y(ADDRESS, imm, "ADDR_PCREL19", OPD_F_SEXT | OPD_F_SHIFT_BY_2,	\

I don't immediately see anything technically wrong with this, but there 
are a lot of minor formatting issues that need to be cleaned up before 
it can be committed.

R.
  
Ezra Sitorus April 10, 2025, 9:28 a.m. UTC | #2
Thanks! I'll address the formatting issues.

Ezra
  

Patch

diff --git a/bfd/elfnn-aarch64.c b/bfd/elfnn-aarch64.c
index 548da1f8b30..8f399204f04 100644
--- a/bfd/elfnn-aarch64.c
+++ b/bfd/elfnn-aarch64.c
@@ -2268,6 +2268,9 @@  elfNN_aarch64_howto_from_bfd_reloc (bfd_reloc_code_real_type code)
   if (code == BFD_RELOC_AARCH64_NONE)
     return &elfNN_aarch64_howto_none;
 
+  if (code == BFD_RELOC_AARCH64_BRANCH9)
+    return &elfNN_aarch64_howto_none;
+
   return NULL;
 }
 
diff --git a/bfd/reloc.c b/bfd/reloc.c
index d3ddafb7305..4182330d0bb 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -7202,7 +7202,7 @@  ENUM
   BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC
 ENUMDOC
   Similar to BFD_RELOC_AARCH64_TLSLD_LDST32_DTPREL_LO12, but no
-  overflow check. 
+  overflow check.
 ENUM
   BFD_RELOC_AARCH64_TLSLD_LDST64_DTPREL_LO12
 ENUMDOC
@@ -7418,6 +7418,12 @@  ENUM
 ENUMDOC
   AArch64 pseudo relocation code to be used internally by the AArch64
   assembler and not (currently) written to any object files.
+ENUM
+  BFD_RELOC_AARCH64_BRANCH9
+ENUMDOC
+	AArch64 9 bit pc-relative conditional branch and compare & branch.
+	The lowest two bits must be zero and are not stored in the
+	instruction, giving an 11 bit signed byte offset.
 ENUM
   BFD_RELOC_TILEPRO_COPY
 ENUMX
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index e071ad11f46..c34eb301b42 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -5175,6 +5175,13 @@  encode_branch_ofs_26 (uint32_t ofs)
   return ofs & ((1 << 26) - 1);
 }
 
+/* encode the 9-bit offset of FEAT_CMPBR compare and branch */
+static inline uint32_t
+encode_cond_branch_ofs_9 (uint32_t ofs)
+{
+  return (ofs & ((1 << 9) - 1)) << 5;
+}
+
 /* encode the 19-bit offset of conditional branch and compare & branch */
 static inline uint32_t
 encode_cond_branch_ofs_19 (uint32_t ofs)
@@ -6388,6 +6395,8 @@  process_omitted_operand (enum aarch64_opnd type, const aarch64_opcode *opcode,
     case AARCH64_OPND_UIMM3_OP2:
     case AARCH64_OPND_IMM:
     case AARCH64_OPND_IMM_2:
+    case AARCH64_OPND_IMMP1_2:
+    case AARCH64_OPND_IMMS1_2:
     case AARCH64_OPND_WIDTH:
     case AARCH64_OPND_UIMM7:
     case AARCH64_OPND_NZCV:
@@ -7154,6 +7163,16 @@  parse_operands (char *str, const aarch64_opcode *opcode)
 	  info->imm.value = val;
 	  break;
 
+	case AARCH64_OPND_IMMP1_2:
+	  po_imm_nc_or_fail ();
+		info->imm.value = val - 1;
+		break;
+
+	case AARCH64_OPND_IMMS1_2:
+	  po_imm_nc_or_fail ();
+		info->imm.value = val + 1;
+		break;
+
 	case AARCH64_OPND_SVE_AIMM:
 	case AARCH64_OPND_SVE_ASIMM:
 	  po_imm_nc_or_fail ();
@@ -7450,6 +7469,7 @@  parse_operands (char *str, const aarch64_opcode *opcode)
 	  info->imm.value = 0;
 	  break;
 
+	case AARCH64_OPND_ADDR_PCREL9:
 	case AARCH64_OPND_ADDR_PCREL14:
 	case AARCH64_OPND_ADDR_PCREL19:
 	case AARCH64_OPND_ADDR_PCREL21:
@@ -7487,8 +7507,10 @@  parse_operands (char *str, const aarch64_opcode *opcode)
 		  case compbranch:
 		  case condbranch:
 		    /* e.g. CBZ or B.COND  */
-		    gas_assert (operands[i] == AARCH64_OPND_ADDR_PCREL19);
-		    inst.reloc.type = BFD_RELOC_AARCH64_BRANCH19;
+		    gas_assert (operands[i] == AARCH64_OPND_ADDR_PCREL9 ||
+							operands[i] == AARCH64_OPND_ADDR_PCREL19);
+		    inst.reloc.type = operands[i] == AARCH64_OPND_ADDR_PCREL9 ?
+							BFD_RELOC_AARCH64_BRANCH9 : BFD_RELOC_AARCH64_BRANCH19;
 		    break;
 		  case testbranch:
 		    /* e.g. TBZ  */
@@ -9670,6 +9692,20 @@  md_apply_fix (fixS * fixP, valueT * valP, segT seg)
 	}
       break;
 
+    case BFD_RELOC_AARCH64_BRANCH9:
+        if (fixP->fx_done || !seg->use_rela_p)
+	{
+	  if (value & 3)
+	    as_bad_where (fixP->fx_file, fixP->fx_line,
+			  _("conditional branch target not word aligned"));
+	  if (signed_overflow (value, 11))
+	    as_bad_where (fixP->fx_file, fixP->fx_line,
+			  _("conditional branch out of range"));
+	  insn = get_aarch64_insn (buf);
+	  insn |= encode_cond_branch_ofs_9 (value >> 2);
+	  put_aarch64_insn (buf, insn);
+	}
+        break;
     case BFD_RELOC_AARCH64_BRANCH19:
       if (fixP->fx_done || !seg->use_rela_p)
 	{
diff --git a/gas/testsuite/gas/aarch64/cmpbr-1.d b/gas/testsuite/gas/aarch64/cmpbr-1.d
new file mode 100644
index 00000000000..02a5aa07066
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/cmpbr-1.d
@@ -0,0 +1,66 @@ 
+#name: Test for FEAT_CMPBR pseudo-instructions
+#objdump: -dr
+
+.*:     file format .*
+
+Disassembly of section .text:
+
+0000000000000000 <a>:
+   0:	74010000 	cbgt	w0, w1, 0 <a>
+   4:	74013fe0 	cbgt	w0, w1, 0 <a>
+   8:	74213fc0 	cbge	w0, w1, 0 <a>
+   c:	74213fa0 	cbge	w0, w1, 0 <a>
+  10:	74413f80 	cbhi	w0, w1, 0 <a>
+  14:	74413f60 	cbhi	w0, w1, 0 <a>
+  18:	74613f40 	cbhs	w0, w1, 0 <a>
+  1c:	74613f20 	cbhs	w0, w1, 0 <a>
+
+0000000000000020 <b>:
+  20:	f4010000 	cbgt	x0, x1, 20 <b>
+  24:	f4013fe0 	cbgt	x0, x1, 20 <b>
+  28:	f4213fc0 	cbge	x0, x1, 20 <b>
+  2c:	f4213fa0 	cbge	x0, x1, 20 <b>
+  30:	f4413f80 	cbhi	x0, x1, 20 <b>
+  34:	f4413f60 	cbhi	x0, x1, 20 <b>
+  38:	f4613f40 	cbhs	x0, x1, 20 <b>
+  3c:	f4613f20 	cbhs	x0, x1, 20 <b>
+
+0000000000000040 <c>:
+  40:	75050000 	cbgt	w0, #10, 40 <c>
+  44:	75053fe0 	cbgt	w0, #10, 40 <c>
+  48:	75263fc0 	cblt	w0, #12, 40 <c>
+  4c:	75263fa1 	cblt	w1, #12, 40 <c>
+  50:	75453f80 	cbhi	w0, #10, 40 <c>
+  54:	75453f60 	cbhi	w0, #10, 40 <c>
+  58:	75663f41 	cblo	w1, #12, 40 <c>
+  5c:	7566bf21 	cblo	w1, #13, 40 <c>
+
+0000000000000060 <d>:
+  60:	f5050000 	cbgt	x0, #10, 60 <d>
+  64:	f5053fe0 	cbgt	x0, #10, 60 <d>
+  68:	f5263fc0 	cblt	x0, #12, 60 <d>
+  6c:	f5263fa1 	cblt	x1, #12, 60 <d>
+  70:	f5453f80 	cbhi	x0, #10, 60 <d>
+  74:	f5453f60 	cbhi	x0, #10, 60 <d>
+  78:	f5663f41 	cblo	x1, #12, 60 <d>
+  7c:	f566bf21 	cblo	x1, #13, 60 <d>
+
+0000000000000080 <e>:
+  80:	74018000 	cbbgt	w0, w1, 80 <e>
+  84:	7401bfe0 	cbbgt	w0, w1, 80 <e>
+  88:	7421bfc0 	cbbge	w0, w1, 80 <e>
+  8c:	7421bfa0 	cbbge	w0, w1, 80 <e>
+  90:	7441bf80 	cbbhi	w0, w1, 80 <e>
+  94:	7441bf60 	cbbhi	w0, w1, 80 <e>
+  98:	7461bf40 	cbbhs	w0, w1, 80 <e>
+  9c:	7461bf20 	cbbhs	w0, w1, 80 <e>
+
+00000000000000a0 <f>:
+  a0:	7401c000 	cbhgt	w0, w1, a0 <f>
+  a4:	7401ffe0 	cbhgt	w0, w1, a0 <f>
+  a8:	7421ffc0 	cbhge	w0, w1, a0 <f>
+  ac:	7421ffa0 	cbhge	w0, w1, a0 <f>
+  b0:	7441ff80 	cbhhi	w0, w1, a0 <f>
+  b4:	7440ff61 	cbhhi	w1, w0, a0 <f>
+  b8:	7461ff40 	cbhhs	w0, w1, a0 <f>
+  bc:	7461ff20 	cbhhs	w0, w1, a0 <f>
diff --git a/gas/testsuite/gas/aarch64/cmpbr-1.s b/gas/testsuite/gas/aarch64/cmpbr-1.s
new file mode 100644
index 00000000000..0d17ebb03c9
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/cmpbr-1.s
@@ -0,0 +1,59 @@ 
+a:
+    cbgt w0, w1, a
+    cblt w1, w0, a
+    cbge w0, w1, a
+    cble w1, w0, a
+    cbhi w0, w1, a
+    cblo w1, w0, a
+    cbhs w0, w1, a
+    cbls w1, w0, a
+
+b:
+    cbgt x0, x1, b
+    cblt x1, x0, b
+    cbge x0, x1, b
+    cble x1, x0, b
+    cbhi x0, x1, b
+    cblo x1, x0, b
+    cbhs x0, x1, b
+    cbls x1, x0, b
+
+c:
+    cbgt w0, #10, c
+    cbge w0, #11, c
+    cblt w0, #12, c
+    cble w1, #11, c
+    cbhi w0, #10, c
+    cbhs w0, #11, c
+    cblo w1, #12, c
+    cbls w1, #12, c
+
+d:
+    cbgt x0, #10, d
+    cbge x0, #11, d
+    cblt x0, #12, d
+    cble x1, #11, d
+    cbhi x0, #10, d
+    cbhs x0, #11, d
+    cblo x1, #12, d
+    cbls x1, #12, d
+
+e:
+    cbbgt w0, w1, e
+    cbblt w1, w0, e
+    cbbge w0, w1, e
+    cbble w1, w0, e
+    cbbhi w0, w1, e
+    cbblo w1, w0, e
+    cbbhs w0, w1, e
+    cbbls w1, w0, e
+
+f:
+    cbhgt w0, w1, f
+    cbhlt w1, w0, f
+    cbhge w0, w1, f
+    cbhle w1, w0, f
+    cbhhi w0, w1, f
+    cbhlo w1, w0, f
+    cbhhs w0, w1, f
+    cbhls w1, w0, f
diff --git a/gas/testsuite/gas/aarch64/cmpbr-bad.d b/gas/testsuite/gas/aarch64/cmpbr-bad.d
new file mode 100644
index 00000000000..802d39e7294
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/cmpbr-bad.d
@@ -0,0 +1,3 @@ 
+#name: Test of invalid cmpbr operands
+#source: cmpbr-bad.s
+#error_output: cmpbr-bad.l
diff --git a/gas/testsuite/gas/aarch64/cmpbr-bad.l b/gas/testsuite/gas/aarch64/cmpbr-bad.l
new file mode 100644
index 00000000000..f705cfd0043
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/cmpbr-bad.l
@@ -0,0 +1,13 @@ 
+.[^ :]+: Assembler messages:
+[^ :]+:[0-9]+: Error: operand mismatch -- `cbgt w0,x1,a'
+[^ :]+:[0-9]+: Info:    did you mean this\?
+[^ :]+:[0-9]+: Info:    	cbgt w0, w1, #0x0
+[^ :]+:[0-9]+: Info:    other valid variant\(s\):
+[^ :]+:[0-9]+: Info:    	cbgt x0, x1, #0x0
+[^ :]+:[0-9]+: Error: immediate value out of range 0 to 63 at operand 2 -- `cbgt w0,#64,a'
+[^ :]+:[0-9]+: Error: operand mismatch -- `cbbgt x0,x1,a'
+[^ :]+:[0-9]+: Info:    did you mean this\?
+[^ :]+:[0-9]+: Info:    	cbbgt w0, w1, #0x0
+[^ :]+:[0-9]+: Error: operand mismatch -- `cbhgt x0,x1,a'
+[^ :]+:[0-9]+: Info:    did you mean this\?
+[^ :]+:[0-9]+: Info:    	cbhgt w0, w1, #0x0
diff --git a/gas/testsuite/gas/aarch64/cmpbr-bad.s b/gas/testsuite/gas/aarch64/cmpbr-bad.s
new file mode 100644
index 00000000000..80b31b827dc
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/cmpbr-bad.s
@@ -0,0 +1,5 @@ 
+a:
+    cbgt w0, x1, a
+    cbgt w0, #64, a
+    cbbgt x0, x1, a
+    cbhgt x0, x1, a
diff --git a/gas/testsuite/gas/aarch64/cmpbr.d b/gas/testsuite/gas/aarch64/cmpbr.d
new file mode 100644
index 00000000000..1ee2d3a0f5d
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/cmpbr.d
@@ -0,0 +1,54 @@ 
+#name: Test for FEAT_CMPBR
+#objdump: -dr
+
+.*:     file format .*
+
+Disassembly of section .text:
+
+0000000000000000 <a>:
+   0:	74010000 	cbgt	w0, w1, 0 <a>
+   4:	74213fe0 	cbge	w0, w1, 0 <a>
+   8:	74413fc0 	cbhi	w0, w1, 0 <a>
+   c:	74613fa0 	cbhs	w0, w1, 0 <a>
+  10:	74c13f80 	cbeq	w0, w1, 0 <a>
+  14:	74e13f60 	cbne	w0, w1, 0 <a>
+
+0000000000000018 <b>:
+  18:	f4010000 	cbgt	x0, x1, 18 <b>
+  1c:	f4213fe0 	cbge	x0, x1, 18 <b>
+  20:	f4413fc0 	cbhi	x0, x1, 18 <b>
+  24:	f4613fa0 	cbhs	x0, x1, 18 <b>
+  28:	f4c13f80 	cbeq	x0, x1, 18 <b>
+  2c:	f4e13f60 	cbne	x0, x1, 18 <b>
+
+0000000000000030 <c>:
+  30:	75010000 	cbgt	w0, #2, 30 <c>
+  34:	75223fe0 	cblt	w0, #4, 30 <c>
+  38:	75433fc0 	cbhi	w0, #6, 30 <c>
+  3c:	75643fa0 	cblo	w0, #8, 30 <c>
+  40:	75c53f80 	cbeq	w0, #10, 30 <c>
+  44:	75e63f60 	cbne	w0, #12, 30 <c>
+
+0000000000000048 <d>:
+  48:	f5070000 	cbgt	x0, #14, 48 <d>
+  4c:	f5283fe0 	cblt	x0, #16, 48 <d>
+  50:	f5493fc0 	cbhi	x0, #18, 48 <d>
+  54:	f56a3fa0 	cblo	x0, #20, 48 <d>
+  58:	f5cb3f80 	cbeq	x0, #22, 48 <d>
+  5c:	f5ec3f60 	cbne	x0, #24, 48 <d>
+
+0000000000000060 <e>:
+  60:	74018000 	cbbgt	w0, w1, 60 <e>
+  64:	7421bfe0 	cbbge	w0, w1, 60 <e>
+  68:	7441bfc0 	cbbhi	w0, w1, 60 <e>
+  6c:	7461bfa0 	cbbhs	w0, w1, 60 <e>
+  70:	74c1bf80 	cbbeq	w0, w1, 60 <e>
+  74:	74e1bf60 	cbbne	w0, w1, 60 <e>
+
+0000000000000078 <f>:
+  78:	7401c000 	cbhgt	w0, w1, 78 <f>
+  7c:	7421ffe0 	cbhge	w0, w1, 78 <f>
+  80:	7441ffc0 	cbhhi	w0, w1, 78 <f>
+  84:	7461ffa0 	cbhhs	w0, w1, 78 <f>
+  88:	74c1ff80 	cbheq	w0, w1, 78 <f>
+  8c:	74e1ff60 	cbhne	w0, w1, 78 <f>
diff --git a/gas/testsuite/gas/aarch64/cmpbr.s b/gas/testsuite/gas/aarch64/cmpbr.s
new file mode 100644
index 00000000000..a259dc8018d
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/cmpbr.s
@@ -0,0 +1,47 @@ 
+a:
+    cbgt w0, w1, a
+    cbge w0, w1, a
+    cbhi w0, w1, a
+    cbhs w0, w1, a
+    cbeq w0, w1, a
+    cbne w0, w1, a
+
+b:
+    cbgt x0, x1, b
+    cbge x0, x1, b
+    cbhi x0, x1, b
+    cbhs x0, x1, b
+    cbeq x0, x1, b
+    cbne x0, x1, b
+
+c:
+    cbgt w0, #2, c
+    cblt w0, #4, c
+    cbhi w0, #6, c
+    cblo w0, #8, c
+    cbeq w0, #10, c
+    cbne w0, #12, c
+
+d:
+    cbgt x0, #14, d
+    cblt x0, #16, d
+    cbhi x0, #18, d
+    cblo x0, #20, d
+    cbeq x0, #22, d
+    cbne x0, #24, d
+
+e:
+    cbbgt w0, w1, e
+    cbbge w0, w1, e
+    cbbhi w0, w1, e
+    cbbhs w0, w1, e
+    cbbeq w0, w1, e
+    cbbne w0, w1, e
+
+f:
+    cbhgt w0, w1, f
+    cbhge w0, w1, f
+    cbhhi w0, w1, f
+    cbhhs w0, w1, f
+    cbheq w0, w1, f
+    cbhne w0, w1, f
diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h
index dfe3f05820a..b6da2d962e6 100644
--- a/include/opcode/aarch64.h
+++ b/include/opcode/aarch64.h
@@ -618,6 +618,8 @@  enum aarch64_opnd
   AARCH64_OPND_WIDTH,	/* Immediate #<width> in e.g. BFI.  */
   AARCH64_OPND_IMM,	/* Immediate.  */
   AARCH64_OPND_IMM_2,	/* Immediate.  */
+  AARCH64_OPND_IMMP1_2,	/* Immediate plus 1.  */
+  AARCH64_OPND_IMMS1_2,	/* Immediate minus 1.  */
   AARCH64_OPND_UIMM3_OP1,/* Unsigned 3-bit immediate in the op1 field.  */
   AARCH64_OPND_UIMM3_OP2,/* Unsigned 3-bit immediate in the op2 field.  */
   AARCH64_OPND_UIMM4,	/* Unsigned 4-bit immediate in the CRm field.  */
@@ -645,6 +647,7 @@  enum aarch64_opnd
   AARCH64_OPND_COND1,	/* Same as the above, but excluding AL and NV.  */
 
   AARCH64_OPND_ADDR_ADRP,	/* Memory address for ADRP */
+  AARCH64_OPND_ADDR_PCREL9,	/* 9-bit PC-relative address for e.g. CB<cc>.  */
   AARCH64_OPND_ADDR_PCREL14,	/* 14-bit PC-relative address for e.g. TBZ.  */
   AARCH64_OPND_ADDR_PCREL19,	/* 19-bit PC-relative address for e.g. LDR.  */
   AARCH64_OPND_ADDR_PCREL21,	/* 21-bit PC-relative address for e.g. ADR.  */
diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
index 4f0c71696fa..e4dc58f439a 100644
--- a/opcodes/aarch64-opc.c
+++ b/opcodes/aarch64-opc.c
@@ -381,6 +381,7 @@  const aarch64_field fields[] =
     { 15,  7 },	/* imm7: in load/store pair pre/post index instructions.  */
     { 13,  8 },	/* imm8: in floating-point scalar move immediate inst.  */
     { 12,  9 },	/* imm9: in load/store pre/post index instructions.  */
+    { 5,   9 },	/* imm9_5: in CB<cc> (immediate).  */
     { 10, 12 },	/* imm12: in ld/st unsigned imm or add/sub shifted inst.  */
     {  5, 14 },	/* imm14: in test bit and branch instructions.  */
     {  0, 16 },	/* imm16_0: in udf instruction. */
@@ -2417,6 +2418,7 @@  operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
 	    }
 	  break;
 
+	case AARCH64_OPND_ADDR_PCREL9:
 	case AARCH64_OPND_ADDR_PCREL14:
 	case AARCH64_OPND_ADDR_PCREL19:
 	case AARCH64_OPND_ADDR_PCREL21:
@@ -4781,6 +4783,7 @@  aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
       snprintf (buf, size, "%s", style_addr (styler, "#0x%" PRIx64 , addr));
       break;
 
+    case AARCH64_OPND_ADDR_PCREL9:
     case AARCH64_OPND_ADDR_PCREL14:
     case AARCH64_OPND_ADDR_PCREL19:
     case AARCH64_OPND_ADDR_PCREL21:
diff --git a/opcodes/aarch64-opc.h b/opcodes/aarch64-opc.h
index 9ab9bdf5123..3086f0285d8 100644
--- a/opcodes/aarch64-opc.h
+++ b/opcodes/aarch64-opc.h
@@ -185,6 +185,7 @@  enum aarch64_field_kind
   FLD_imm7,
   FLD_imm8,
   FLD_imm9,
+  FLD_imm9_5,
   FLD_imm12,
   FLD_imm14,
   FLD_imm16_0,
diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h
index 8b64eb07067..bb560139d1e 100644
--- a/opcodes/aarch64-tbl.h
+++ b/opcodes/aarch64-tbl.h
@@ -136,6 +136,19 @@ 
   QLF2(X,NIL),			\
 }
 
+/* e.g. CBBGT <Wt>, <Wm>, <label>.  */
+#define QL_W2_PCREL		\
+{				\
+  QLF3(W,W,NIL),		\
+}
+
+/* e.g. CBGT <Wt>, #<imm6>, <label>.  */
+#define QL_R_IMM_PCREL		\
+{				\
+  QLF3(W,imm_0_63,NIL),		\
+  QLF3(X,imm_0_63,NIL),		\
+}
+
 /* e.g. LDR <Dt>, <label>.  */
 #define QL_FP_PCREL		\
 {				\
@@ -3965,6 +3978,50 @@  const struct aarch64_opcode aarch64_opcode_table[] =
   CORE_INSN ("cbnz", 0x35000000, 0x7f000000, compbranch, 0, OP2 (Rt, ADDR_PCREL19), QL_R_PCREL, F_SF),
   /* Conditional branch (immediate).  */
   CORE_INSN ("b.c", 0x54000000, 0xff000010, condbranch, 0, OP1 (ADDR_PCREL19), QL_PCREL_NIL, F_COND),
+  /* Compare registers and branch. */
+  CORE_INSN ("cbgt", 0x74000000, 0x7fe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF | F_ALIAS),
+  CORE_INSN ("cblt", 0x74000000, 0x7fe0c000, compbranch, 0, OP3 (Rm, Rt, ADDR_PCREL9), QL_R2NIL, F_SF | F_HAS_ALIAS),
+  CORE_INSN ("cbge", 0x74200000, 0x7fe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF | F_ALIAS),
+  CORE_INSN ("cble", 0x74200000, 0x7fe0c000, compbranch, 0, OP3 (Rm, Rt, ADDR_PCREL9), QL_R2NIL, F_SF | F_HAS_ALIAS),
+  CORE_INSN ("cbhi", 0x74400000, 0x7fe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF | F_ALIAS),
+  CORE_INSN ("cblo", 0x74400000, 0x7fe0c000, compbranch, 0, OP3 (Rm, Rt, ADDR_PCREL9), QL_R2NIL, F_SF | F_HAS_ALIAS),
+  CORE_INSN ("cbhs", 0x74600000, 0x7fe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF | F_ALIAS),
+  CORE_INSN ("cbls", 0x74600000, 0x7fe0c000, compbranch, 0, OP3 (Rm, Rt, ADDR_PCREL9), QL_R2NIL, F_SF | F_HAS_ALIAS),
+  CORE_INSN ("cbeq", 0x74c00000, 0x7fe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF),
+  CORE_INSN ("cbne", 0x74e00000, 0x7fe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF),
+  /* Compare register with immediate and branch.  */
+  CORE_INSN ("cbgt", 0x75000000, 0x7fe04000, compbranch, 0, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_ALIAS),
+  CORE_INSN ("cbge", 0x75000000, 0x7fe04000, compbranch, 0, OP3 (Rt, IMMP1_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_HAS_ALIAS),
+  CORE_INSN ("cblt", 0x75200000, 0x7fe04000, compbranch, 0, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_ALIAS),
+  CORE_INSN ("cble", 0x75200000, 0x7fe04000, compbranch, 0, OP3 (Rt, IMMS1_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_HAS_ALIAS),
+  CORE_INSN ("cbhi", 0x75400000, 0x7fe04000, compbranch, 0, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_ALIAS),
+  CORE_INSN ("cbhs", 0x75400000, 0x7fe04000, compbranch, 0, OP3 (Rt, IMMP1_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_HAS_ALIAS),
+  CORE_INSN ("cblo", 0x75600000, 0x7fe04000, compbranch, 0, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_ALIAS),
+  CORE_INSN ("cbls", 0x75600000, 0x7fe04000, compbranch, 0, OP3 (Rt, IMMS1_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_HAS_ALIAS),
+  CORE_INSN ("cbeq", 0x75c00000, 0x7fe04000, compbranch, 0, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF),
+  CORE_INSN ("cbne", 0x75e00000, 0x7fe04000, compbranch, 0, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF),
+  // /* Compare bytes and branch.  */
+  CORE_INSN ("cbbgt", 0x74008000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS),
+  CORE_INSN ("cbblt", 0x74008000, 0xffe0c000, compbranch, 0, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
+  CORE_INSN ("cbbge", 0x74208000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS),
+  CORE_INSN ("cbble", 0x74208000, 0xffe0c000, compbranch, 0, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
+  CORE_INSN ("cbbhi", 0x74408000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS),
+  CORE_INSN ("cbblo", 0x74408000, 0xffe0c000, compbranch, 0, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
+  CORE_INSN ("cbbhs", 0x74608000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS),
+  CORE_INSN ("cbbls", 0x74608000, 0xffe0c000, compbranch, 0, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
+  CORE_INSN ("cbbeq", 0x74c08000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, 0),
+  CORE_INSN ("cbbne", 0x74e08000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, 0),
+  // /* Compare halfwords and branch.  */
+  CORE_INSN ("cbhgt", 0x7400c000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS),
+  CORE_INSN ("cbhlt", 0x7400c000, 0xffe0c000, compbranch, 0, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
+  CORE_INSN ("cbhge", 0x7420c000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS),
+  CORE_INSN ("cbhle", 0x7420c000, 0xffe0c000, compbranch, 0, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
+  CORE_INSN ("cbhhi", 0x7440c000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS),
+  CORE_INSN ("cbhlo", 0x7440c000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
+  CORE_INSN ("cbhhs", 0x7460c000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS),
+  CORE_INSN ("cbhls", 0x7460c000, 0xffe0c000, compbranch, 0, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
+  CORE_INSN ("cbheq", 0x74c0c000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, 0),
+  CORE_INSN ("cbhne", 0x74e0c000, 0xffe0c000, compbranch, 0, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, 0),
   /* Conditional compare (immediate).  */
   CORE_INSN ("ccmn", 0x3a400800, 0x7fe00c10, condcmp_imm, 0, OP4 (Rn, CCMP_IMM, NZCV, COND), QL_CCMP_IMM, F_SF),
   CORE_INSN ("ccmp", 0x7a400800, 0x7fe00c10, condcmp_imm, 0, OP4 (Rn, CCMP_IMM, NZCV, COND), QL_CCMP_IMM, F_SF),
@@ -7126,6 +7183,8 @@  const struct aarch64_opcode aarch64_opcode_table[] =
       "the width of the bit-field")					\
     Y(IMMEDIATE, imm, "IMM", 0, F(FLD_imm6_10), "an immediate")         \
     Y(IMMEDIATE, imm, "IMM_2", 0, F(FLD_imm6_15), "an immediate")       \
+    Y(IMMEDIATE, imm, "IMMP1_2", 0, F(FLD_imm6_15), "an immediate plus 1")       \
+    Y(IMMEDIATE, imm, "IMMS1_2", 0, F(FLD_imm6_15), "an immediate minus 1")       \
     Y(IMMEDIATE, imm, "UIMM3_OP1", 0, F(FLD_op1),			\
       "a 3-bit unsigned immediate")					\
     Y(IMMEDIATE, imm, "UIMM3_OP2", 0, F(FLD_op2),			\
@@ -7170,6 +7229,8 @@  const struct aarch64_opcode aarch64_opcode_table[] =
       "one of the standard conditions, excluding AL and NV.")		\
     X(ADDRESS, 0, ext_imm, "ADDR_ADRP", OPD_F_SEXT, F(FLD_immhi, FLD_immlo),\
       "21-bit PC-relative address of a 4KB page")			\
+    Y(ADDRESS, imm, "ADDR_PCREL9", OPD_F_SEXT | OPD_F_SHIFT_BY_2,	\
+      F(FLD_imm9_5), "9-bit PC-relative address")			\
     Y(ADDRESS, imm, "ADDR_PCREL14", OPD_F_SEXT | OPD_F_SHIFT_BY_2,	\
       F(FLD_imm14), "14-bit PC-relative address")			\
     Y(ADDRESS, imm, "ADDR_PCREL19", OPD_F_SEXT | OPD_F_SHIFT_BY_2,	\