On Tue, Apr 15, 2025 at 09:49:43AM +0100, Ezra.Sitorus@arm.com wrote:
Thanks for the patch - I think it's close to ready, but I have a few comments
below.
> 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
I've no objection to this much detail, but I think a simple "Add support for
FEAT_CMPBR" as the patch header would be sufficient - the list of instructions
is then obvious from either the spec or the patch content.
>
> 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
I don't think it's necessary (or desirable) to give a list of lengthy
documentation links. If you want to give a link, I'd stick to just
https://developer.arm.com/documentation/ddi0602/2024-12.
> ---
> This has addressed the formatting issues raised in v1. Regression tested on aarch64-none-linux-gnu.
> I still don't have commit rights - could somebody commit this if it looks ok?
>
> Ezra
>
> bfd/elfnn-aarch64.c | 3 ++
> bfd/reloc.c | 8 +++-
> gas/config/tc-aarch64.c | 42 ++++++++++++++++-
> gas/doc/c-aarch64.texi | 2 +
> gas/testsuite/gas/aarch64/cmpbr-1.d | 67 +++++++++++++++++++++++++++
> gas/testsuite/gas/aarch64/cmpbr-1.s | 59 +++++++++++++++++++++++
> gas/testsuite/gas/aarch64/cmpbr-bad.d | 4 ++
> gas/testsuite/gas/aarch64/cmpbr-bad.l | 13 ++++++
> gas/testsuite/gas/aarch64/cmpbr-bad.s | 5 ++
> gas/testsuite/gas/aarch64/cmpbr.d | 55 ++++++++++++++++++++++
> gas/testsuite/gas/aarch64/cmpbr.s | 47 +++++++++++++++++++
> include/opcode/aarch64.h | 5 ++
> opcodes/aarch64-opc.c | 3 ++
> opcodes/aarch64-opc.h | 1 +
> opcodes/aarch64-tbl.h | 66 ++++++++++++++++++++++++++
> 15 files changed, 377 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..1aa0add7790 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.
It's best to avoid unrelated format changes on code that you aren't otherwise
touching, so this hunk should be dropped.
> 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/doc/c-aarch64.texi b/gas/doc/c-aarch64.texi
> index 10888d1e78f..5927998c0bd 100644
> --- a/gas/doc/c-aarch64.texi
> +++ b/gas/doc/c-aarch64.texi
> @@ -229,6 +229,8 @@ automatically cause those extensions to be disabled.
> @tab Enable the Lookup Table (LUT) extension.
> @item @code{memtag} @tab
> @tab Enable Armv8.5-A Memory Tagging Extensions.
> +@item @code{cmpbr} @tab
> + @tab Enable Compare and Branch instructions.
This list is in alphabetical order; please preserve that.
> @item @code{mops} @tab
> @tab Enable Armv8.8-A memcpy and memset acceleration instructions
> @item @code{pan} @tab
> diff --git a/gas/testsuite/gas/aarch64/cmpbr-1.d b/gas/testsuite/gas/aarch64/cmpbr-1.d
> new file mode 100644
> index 00000000000..d5e02a09f4b
> --- /dev/null
> +++ b/gas/testsuite/gas/aarch64/cmpbr-1.d
> @@ -0,0 +1,67 @@
> +#name: Test for FEAT_CMPBR pseudo-instructions
> +#as: -march=armv8-a+cmpbr
> +#objdump: -dr
> +
> +.*: file format .*
> +
> +Disassembly of section .text:
> +
> +.* <a>:
> +.*: 74010000 cbgt w0, w1, 0 <a>
> +.*: 74013fe0 cbgt w0, w1, 0 <a>
> +.*: 74213fc0 cbge w0, w1, 0 <a>
> +.*: 74213fa0 cbge w0, w1, 0 <a>
> +.*: 74413f80 cbhi w0, w1, 0 <a>
> +.*: 74413f60 cbhi w0, w1, 0 <a>
> +.*: 74613f40 cbhs w0, w1, 0 <a>
> +.*: 74613f20 cbhs w0, w1, 0 <a>
> +
> +.* <b>:
> +.*: f4010000 cbgt x0, x1, 20 <b>
> +.*: f4013fe0 cbgt x0, x1, 20 <b>
> +.*: f4213fc0 cbge x0, x1, 20 <b>
> +.*: f4213fa0 cbge x0, x1, 20 <b>
> +.*: f4413f80 cbhi x0, x1, 20 <b>
> +.*: f4413f60 cbhi x0, x1, 20 <b>
> +.*: f4613f40 cbhs x0, x1, 20 <b>
> +.*: f4613f20 cbhs x0, x1, 20 <b>
> +
> +.* <c>:
> +.*: 75050000 cbgt w0, #10, 40 <c>
> +.*: 75053fe0 cbgt w0, #10, 40 <c>
> +.*: 75263fc0 cblt w0, #12, 40 <c>
> +.*: 75263fa1 cblt w1, #12, 40 <c>
> +.*: 75453f80 cbhi w0, #10, 40 <c>
> +.*: 75453f60 cbhi w0, #10, 40 <c>
> +.*: 75663f41 cblo w1, #12, 40 <c>
> +.*: 7566bf21 cblo w1, #13, 40 <c>
> +
> +.* <d>:
> +.*: f5050000 cbgt x0, #10, 60 <d>
> +.*: f5053fe0 cbgt x0, #10, 60 <d>
> +.*: f5263fc0 cblt x0, #12, 60 <d>
> +.*: f5263fa1 cblt x1, #12, 60 <d>
> +.*: f5453f80 cbhi x0, #10, 60 <d>
> +.*: f5453f60 cbhi x0, #10, 60 <d>
> +.*: f5663f41 cblo x1, #12, 60 <d>
> +.*: f566bf21 cblo x1, #13, 60 <d>
> +
> +.* <e>:
> +.*: 74018000 cbbgt w0, w1, 80 <e>
> +.*: 7401bfe0 cbbgt w0, w1, 80 <e>
> +.*: 7421bfc0 cbbge w0, w1, 80 <e>
> +.*: 7421bfa0 cbbge w0, w1, 80 <e>
> +.*: 7441bf80 cbbhi w0, w1, 80 <e>
> +.*: 7441bf60 cbbhi w0, w1, 80 <e>
> +.*: 7461bf40 cbbhs w0, w1, 80 <e>
> +.*: 7461bf20 cbbhs w0, w1, 80 <e>
> +
> +.* <f>:
> +.*: 7401c000 cbhgt w0, w1, a0 <f>
> +.*: 7401ffe0 cbhgt w0, w1, a0 <f>
> +.*: 7421ffc0 cbhge w0, w1, a0 <f>
> +.*: 7421ffa0 cbhge w0, w1, a0 <f>
> +.*: 7441ff80 cbhhi w0, w1, a0 <f>
> +.*: 7440ff61 cbhhi w1, w0, a0 <f>
> +.*: 7461ff40 cbhhs w0, w1, a0 <f>
> +.*: 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..bd46851faa2
> --- /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..6487979e85f
> --- /dev/null
> +++ b/gas/testsuite/gas/aarch64/cmpbr-bad.d
> @@ -0,0 +1,4 @@
> +#name: Test of invalid cmpbr operands
> +#source: cmpbr-bad.s
> +#as: -march=armv8-a+cmpbr
> +#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..8fb1e617254
> --- /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..dd693496822
> --- /dev/null
> +++ b/gas/testsuite/gas/aarch64/cmpbr.d
> @@ -0,0 +1,55 @@
> +#name: Test for FEAT_CMPBR
> +#as: -march=armv8-a+cmpbr
> +#objdump: -dr
> +
> +.*: file format .*
> +
> +Disassembly of section .text:
> +
> +.* <a>:
> +.*: 74010000 cbgt w0, w1, 0 <a>
> +.*: 74213fe0 cbge w0, w1, 0 <a>
> +.*: 74413fc0 cbhi w0, w1, 0 <a>
> +.*: 74613fa0 cbhs w0, w1, 0 <a>
> +.*: 74c13f80 cbeq w0, w1, 0 <a>
> +.*: 74e13f60 cbne w0, w1, 0 <a>
> +
> +.* <b>:
> +.*: f4010000 cbgt x0, x1, 18 <b>
> +.*: f4213fe0 cbge x0, x1, 18 <b>
> +.*: f4413fc0 cbhi x0, x1, 18 <b>
> +.*: f4613fa0 cbhs x0, x1, 18 <b>
> +.*: f4c13f80 cbeq x0, x1, 18 <b>
> +.*: f4e13f60 cbne x0, x1, 18 <b>
> +
> +.* <c>:
> +.*: 75010000 cbgt w0, #2, 30 <c>
> +.*: 75223fe0 cblt w0, #4, 30 <c>
> +.*: 75433fc0 cbhi w0, #6, 30 <c>
> +.*: 75643fa0 cblo w0, #8, 30 <c>
> +.*: 75c53f80 cbeq w0, #10, 30 <c>
> +.*: 75e63f60 cbne w0, #12, 30 <c>
> +
> +.* <d>:
> +.*: f5070000 cbgt x0, #14, 48 <d>
> +.*: f5283fe0 cblt x0, #16, 48 <d>
> +.*: f5493fc0 cbhi x0, #18, 48 <d>
> +.*: f56a3fa0 cblo x0, #20, 48 <d>
> +.*: f5cb3f80 cbeq x0, #22, 48 <d>
> +.*: f5ec3f60 cbne x0, #24, 48 <d>
> +
> +.* <e>:
> +.*: 74018000 cbbgt w0, w1, 60 <e>
> +.*: 7421bfe0 cbbge w0, w1, 60 <e>
> +.*: 7441bfc0 cbbhi w0, w1, 60 <e>
> +.*: 7461bfa0 cbbhs w0, w1, 60 <e>
> +.*: 74c1bf80 cbbeq w0, w1, 60 <e>
> +.*: 74e1bf60 cbbne w0, w1, 60 <e>
> +
> +.* <f>:
> +.*: 7401c000 cbhgt w0, w1, 78 <f>
> +.*: 7421ffe0 cbhge w0, w1, 78 <f>
> +.*: 7441ffc0 cbhhi w0, w1, 78 <f>
> +.*: 7461ffa0 cbhhs w0, w1, 78 <f>
> +.*: 74c1ff80 cbheq w0, w1, 78 <f>
> +.*: 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..95d3fae5bab
> --- /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
I'd like to see more thorough tests for each opcode table entry, that verify
that every variable bit in the entry can be set to both 0 and 1 and verify that
operands (and any separate fields within an operand) are in the correct order.
There are various ways to arrange this, but usually I start with a test in
which all the variable bits are zero, then set each operand in turn to its
all-ones value. If there's multiple qualifier sequences allowed, then I'd
usually repeat this for each qualifier sequence.
I'd also like to see tests for the new IMMP1_2 and IMMS1_2 operands that show
that there are still sensible error messages for the value 0 and 63
respectively (which would normally be in range for a 6-bit immediate).
> 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..d4ab134e0a4 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), \
> +}
> +
Could you use more generic names - e.g. QL_W2NIL to match the existing
QL_R2NIL? Then it can be reused when useful without worrying about the name
being wrong (as is the case with the equivalent QL_W2_LDST_EXC macro), and it's
more consistent with the other instructions you've added.
> +/* 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 \
> { \
> @@ -2737,6 +2750,8 @@ static const aarch64_feature_set aarch64_feature_predres =
> AARCH64_FEATURE (PREDRES);
> static const aarch64_feature_set aarch64_feature_predres2 =
> AARCH64_FEATURES (2, PREDRES, PREDRES2);
> +static const aarch64_feature_set aarch64_feature_cmpbr =
> + AARCH64_FEATURE (CMPBR);
> static const aarch64_feature_set aarch64_feature_memtag =
> AARCH64_FEATURE (MEMTAG);
> static const aarch64_feature_set aarch64_feature_bfloat16 =
> @@ -2897,6 +2912,7 @@ static const aarch64_feature_set aarch64_feature_sve2p1_sme2p1 =
> #define SB &aarch64_feature_sb
> #define PREDRES &aarch64_feature_predres
> #define PREDRES2 &aarch64_feature_predres2
> +#define CMPBR &aarch64_feature_cmpbr
> #define MEMTAG &aarch64_feature_memtag
> #define TME &aarch64_feature_tme
> #define SVE2 &aarch64_feature_sve2
> @@ -3022,6 +3038,8 @@ static const aarch64_feature_set aarch64_feature_sve2p1_sme2p1 =
> { NAME, OPCODE, MASK, CLASS, 0, SB, OPS, QUALS, FLAGS, 0, 0, NULL }
> #define PREDRES_INSN(NAME,OPCODE,MASK,CLASS,OPS,QUALS,FLAGS) \
> { NAME, OPCODE, MASK, CLASS, 0, PREDRES, OPS, QUALS, FLAGS, 0, 0, NULL }
> +#define CMPBR_INSN(NAME,OPCODE,MASK,CLASS,OPS,QUALS,FLAGS) \
> + { NAME, OPCODE, MASK, CLASS, 0, CMPBR, OPS, QUALS, FLAGS, 0, 0, NULL }
> #define MEMTAG_INSN(NAME,OPCODE,MASK,CLASS,OPS,QUALS,FLAGS) \
> { NAME, OPCODE, MASK, CLASS, 0, MEMTAG, OPS, QUALS, FLAGS, 0, 0, NULL }
> #define _TME_INSN(NAME,OPCODE,MASK,CLASS,OP,OPS,QUALS,FLAGS) \
> @@ -3965,6 +3983,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. */
> + CMPBR_INSN ("cbgt", 0x74000000, 0x7fe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF | F_HAS_ALIAS),
> + CMPBR_INSN ("cblt", 0x74000000, 0x7fe0c000, compbranch, OP3 (Rm, Rt, ADDR_PCREL9), QL_R2NIL, F_SF | F_ALIAS | F_PSEUDO),
> + CMPBR_INSN ("cbge", 0x74200000, 0x7fe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF | F_HAS_ALIAS),
> + CMPBR_INSN ("cble", 0x74200000, 0x7fe0c000, compbranch, OP3 (Rm, Rt, ADDR_PCREL9), QL_R2NIL, F_SF | F_ALIAS | F_PSEUDO),
> + CMPBR_INSN ("cbhi", 0x74400000, 0x7fe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF | F_HAS_ALIAS),
> + CMPBR_INSN ("cblo", 0x74400000, 0x7fe0c000, compbranch, OP3 (Rm, Rt, ADDR_PCREL9), QL_R2NIL, F_SF | F_ALIAS | F_PSEUDO),
> + CMPBR_INSN ("cbhs", 0x74600000, 0x7fe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF | F_HAS_ALIAS),
> + CMPBR_INSN ("cbls", 0x74600000, 0x7fe0c000, compbranch, OP3 (Rm, Rt, ADDR_PCREL9), QL_R2NIL, F_SF | F_ALIAS | F_PSEUDO),
> + CMPBR_INSN ("cbeq", 0x74c00000, 0x7fe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF),
> + CMPBR_INSN ("cbne", 0x74e00000, 0x7fe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF),
> + /* Compare register with immediate and branch. */
> + CMPBR_INSN ("cbgt", 0x75000000, 0x7fe04000, compbranch, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_HAS_ALIAS),
> + CMPBR_INSN ("cbge", 0x75000000, 0x7fe04000, compbranch, OP3 (Rt, IMMP1_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_ALIAS | F_PSEUDO),
> + CMPBR_INSN ("cblt", 0x75200000, 0x7fe04000, compbranch, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_HAS_ALIAS),
> + CMPBR_INSN ("cble", 0x75200000, 0x7fe04000, compbranch, OP3 (Rt, IMMS1_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_ALIAS | F_PSEUDO),
> + CMPBR_INSN ("cbhi", 0x75400000, 0x7fe04000, compbranch, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_HAS_ALIAS),
> + CMPBR_INSN ("cbhs", 0x75400000, 0x7fe04000, compbranch, OP3 (Rt, IMMP1_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_ALIAS | F_PSEUDO),
> + CMPBR_INSN ("cblo", 0x75600000, 0x7fe04000, compbranch, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_HAS_ALIAS),
> + CMPBR_INSN ("cbls", 0x75600000, 0x7fe04000, compbranch, OP3 (Rt, IMMS1_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_ALIAS | F_PSEUDO),
> + CMPBR_INSN ("cbeq", 0x75c00000, 0x7fe04000, compbranch, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF),
> + CMPBR_INSN ("cbne", 0x75e00000, 0x7fe04000, compbranch, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF),
> + /* Compare bytes and branch. */
> + CMPBR_INSN ("cbbgt", 0x74008000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
> + CMPBR_INSN ("cbblt", 0x74008000, 0xffe0c000, compbranch, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS | F_PSEUDO),
> + CMPBR_INSN ("cbbge", 0x74208000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
> + CMPBR_INSN ("cbble", 0x74208000, 0xffe0c000, compbranch, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS | F_PSEUDO),
> + CMPBR_INSN ("cbbhi", 0x74408000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
> + CMPBR_INSN ("cbblo", 0x74408000, 0xffe0c000, compbranch, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS | F_PSEUDO),
> + CMPBR_INSN ("cbbhs", 0x74608000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
> + CMPBR_INSN ("cbbls", 0x74608000, 0xffe0c000, compbranch, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS | F_PSEUDO),
> + CMPBR_INSN ("cbbeq", 0x74c08000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, 0),
> + CMPBR_INSN ("cbbne", 0x74e08000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, 0),
> + /* Compare halfwords and branch. */
> + CMPBR_INSN ("cbhgt", 0x7400c000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
> + CMPBR_INSN ("cbhlt", 0x7400c000, 0xffe0c000, compbranch, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS | F_PSEUDO),
> + CMPBR_INSN ("cbhge", 0x7420c000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
> + CMPBR_INSN ("cbhle", 0x7420c000, 0xffe0c000, compbranch, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS | F_PSEUDO),
> + CMPBR_INSN ("cbhhi", 0x7440c000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
> + CMPBR_INSN ("cbhlo", 0x7440c000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS | F_PSEUDO),
> + CMPBR_INSN ("cbhhs", 0x7460c000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
> + CMPBR_INSN ("cbhls", 0x7460c000, 0xffe0c000, compbranch, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS | F_PSEUDO),
> + CMPBR_INSN ("cbheq", 0x74c0c000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, 0),
> + CMPBR_INSN ("cbhne", 0x74e0c000, 0xffe0c000, compbranch, 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 +7188,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 +7234,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, \
> --
> 2.45.2
@@ -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;
}
@@ -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
@@ -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,11 @@ 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 +9693,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)
{
@@ -10672,6 +10709,7 @@ static const struct aarch64_option_cpu_value_table aarch64_features[] = {
{"rng", AARCH64_FEATURE (RNG), AARCH64_NO_FEATURES},
{"ssbs", AARCH64_FEATURE (SSBS), AARCH64_NO_FEATURES},
{"memtag", AARCH64_FEATURE (MEMTAG), AARCH64_NO_FEATURES},
+ {"cmpbr", AARCH64_FEATURE (CMPBR), AARCH64_NO_FEATURES},
{"sve2", AARCH64_FEATURE (SVE2), AARCH64_FEATURE (SVE)},
{"sve2-sm4", AARCH64_FEATURE (SVE2_SM4),
AARCH64_FEATURES (2, SVE2, SM4)},
@@ -229,6 +229,8 @@ automatically cause those extensions to be disabled.
@tab Enable the Lookup Table (LUT) extension.
@item @code{memtag} @tab
@tab Enable Armv8.5-A Memory Tagging Extensions.
+@item @code{cmpbr} @tab
+ @tab Enable Compare and Branch instructions.
@item @code{mops} @tab
@tab Enable Armv8.8-A memcpy and memset acceleration instructions
@item @code{pan} @tab
new file mode 100644
@@ -0,0 +1,67 @@
+#name: Test for FEAT_CMPBR pseudo-instructions
+#as: -march=armv8-a+cmpbr
+#objdump: -dr
+
+.*: file format .*
+
+Disassembly of section .text:
+
+.* <a>:
+.*: 74010000 cbgt w0, w1, 0 <a>
+.*: 74013fe0 cbgt w0, w1, 0 <a>
+.*: 74213fc0 cbge w0, w1, 0 <a>
+.*: 74213fa0 cbge w0, w1, 0 <a>
+.*: 74413f80 cbhi w0, w1, 0 <a>
+.*: 74413f60 cbhi w0, w1, 0 <a>
+.*: 74613f40 cbhs w0, w1, 0 <a>
+.*: 74613f20 cbhs w0, w1, 0 <a>
+
+.* <b>:
+.*: f4010000 cbgt x0, x1, 20 <b>
+.*: f4013fe0 cbgt x0, x1, 20 <b>
+.*: f4213fc0 cbge x0, x1, 20 <b>
+.*: f4213fa0 cbge x0, x1, 20 <b>
+.*: f4413f80 cbhi x0, x1, 20 <b>
+.*: f4413f60 cbhi x0, x1, 20 <b>
+.*: f4613f40 cbhs x0, x1, 20 <b>
+.*: f4613f20 cbhs x0, x1, 20 <b>
+
+.* <c>:
+.*: 75050000 cbgt w0, #10, 40 <c>
+.*: 75053fe0 cbgt w0, #10, 40 <c>
+.*: 75263fc0 cblt w0, #12, 40 <c>
+.*: 75263fa1 cblt w1, #12, 40 <c>
+.*: 75453f80 cbhi w0, #10, 40 <c>
+.*: 75453f60 cbhi w0, #10, 40 <c>
+.*: 75663f41 cblo w1, #12, 40 <c>
+.*: 7566bf21 cblo w1, #13, 40 <c>
+
+.* <d>:
+.*: f5050000 cbgt x0, #10, 60 <d>
+.*: f5053fe0 cbgt x0, #10, 60 <d>
+.*: f5263fc0 cblt x0, #12, 60 <d>
+.*: f5263fa1 cblt x1, #12, 60 <d>
+.*: f5453f80 cbhi x0, #10, 60 <d>
+.*: f5453f60 cbhi x0, #10, 60 <d>
+.*: f5663f41 cblo x1, #12, 60 <d>
+.*: f566bf21 cblo x1, #13, 60 <d>
+
+.* <e>:
+.*: 74018000 cbbgt w0, w1, 80 <e>
+.*: 7401bfe0 cbbgt w0, w1, 80 <e>
+.*: 7421bfc0 cbbge w0, w1, 80 <e>
+.*: 7421bfa0 cbbge w0, w1, 80 <e>
+.*: 7441bf80 cbbhi w0, w1, 80 <e>
+.*: 7441bf60 cbbhi w0, w1, 80 <e>
+.*: 7461bf40 cbbhs w0, w1, 80 <e>
+.*: 7461bf20 cbbhs w0, w1, 80 <e>
+
+.* <f>:
+.*: 7401c000 cbhgt w0, w1, a0 <f>
+.*: 7401ffe0 cbhgt w0, w1, a0 <f>
+.*: 7421ffc0 cbhge w0, w1, a0 <f>
+.*: 7421ffa0 cbhge w0, w1, a0 <f>
+.*: 7441ff80 cbhhi w0, w1, a0 <f>
+.*: 7440ff61 cbhhi w1, w0, a0 <f>
+.*: 7461ff40 cbhhs w0, w1, a0 <f>
+.*: 7461ff20 cbhhs w0, w1, a0 <f>
new file mode 100644
@@ -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
new file mode 100644
@@ -0,0 +1,4 @@
+#name: Test of invalid cmpbr operands
+#source: cmpbr-bad.s
+#as: -march=armv8-a+cmpbr
+#error_output: cmpbr-bad.l
new file mode 100644
@@ -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
new file mode 100644
@@ -0,0 +1,5 @@
+a:
+ cbgt w0, x1, a
+ cbgt w0, #64, a
+ cbbgt x0, x1, a
+ cbhgt x0, x1, a
new file mode 100644
@@ -0,0 +1,55 @@
+#name: Test for FEAT_CMPBR
+#as: -march=armv8-a+cmpbr
+#objdump: -dr
+
+.*: file format .*
+
+Disassembly of section .text:
+
+.* <a>:
+.*: 74010000 cbgt w0, w1, 0 <a>
+.*: 74213fe0 cbge w0, w1, 0 <a>
+.*: 74413fc0 cbhi w0, w1, 0 <a>
+.*: 74613fa0 cbhs w0, w1, 0 <a>
+.*: 74c13f80 cbeq w0, w1, 0 <a>
+.*: 74e13f60 cbne w0, w1, 0 <a>
+
+.* <b>:
+.*: f4010000 cbgt x0, x1, 18 <b>
+.*: f4213fe0 cbge x0, x1, 18 <b>
+.*: f4413fc0 cbhi x0, x1, 18 <b>
+.*: f4613fa0 cbhs x0, x1, 18 <b>
+.*: f4c13f80 cbeq x0, x1, 18 <b>
+.*: f4e13f60 cbne x0, x1, 18 <b>
+
+.* <c>:
+.*: 75010000 cbgt w0, #2, 30 <c>
+.*: 75223fe0 cblt w0, #4, 30 <c>
+.*: 75433fc0 cbhi w0, #6, 30 <c>
+.*: 75643fa0 cblo w0, #8, 30 <c>
+.*: 75c53f80 cbeq w0, #10, 30 <c>
+.*: 75e63f60 cbne w0, #12, 30 <c>
+
+.* <d>:
+.*: f5070000 cbgt x0, #14, 48 <d>
+.*: f5283fe0 cblt x0, #16, 48 <d>
+.*: f5493fc0 cbhi x0, #18, 48 <d>
+.*: f56a3fa0 cblo x0, #20, 48 <d>
+.*: f5cb3f80 cbeq x0, #22, 48 <d>
+.*: f5ec3f60 cbne x0, #24, 48 <d>
+
+.* <e>:
+.*: 74018000 cbbgt w0, w1, 60 <e>
+.*: 7421bfe0 cbbge w0, w1, 60 <e>
+.*: 7441bfc0 cbbhi w0, w1, 60 <e>
+.*: 7461bfa0 cbbhs w0, w1, 60 <e>
+.*: 74c1bf80 cbbeq w0, w1, 60 <e>
+.*: 74e1bf60 cbbne w0, w1, 60 <e>
+
+.* <f>:
+.*: 7401c000 cbhgt w0, w1, 78 <f>
+.*: 7421ffe0 cbhge w0, w1, 78 <f>
+.*: 7441ffc0 cbhhi w0, w1, 78 <f>
+.*: 7461ffa0 cbhhs w0, w1, 78 <f>
+.*: 74c1ff80 cbheq w0, w1, 78 <f>
+.*: 74e1ff60 cbhne w0, w1, 78 <f>
new file mode 100644
@@ -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
@@ -135,6 +135,8 @@ enum aarch64_feature_bit {
AARCH64_FEATURE_ID_PFR2,
/* SSBS mechanism enabled. */
AARCH64_FEATURE_SSBS,
+ /* Compare and branch instructions. */
+ AARCH64_FEATURE_CMPBR,
/* Memory Tagging Extension. */
AARCH64_FEATURE_MEMTAG,
/* Transactional Memory Extension. */
@@ -618,6 +620,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 +649,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. */
@@ -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:
@@ -185,6 +185,7 @@ enum aarch64_field_kind
FLD_imm7,
FLD_imm8,
FLD_imm9,
+ FLD_imm9_5,
FLD_imm12,
FLD_imm14,
FLD_imm16_0,
@@ -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 \
{ \
@@ -2737,6 +2750,8 @@ static const aarch64_feature_set aarch64_feature_predres =
AARCH64_FEATURE (PREDRES);
static const aarch64_feature_set aarch64_feature_predres2 =
AARCH64_FEATURES (2, PREDRES, PREDRES2);
+static const aarch64_feature_set aarch64_feature_cmpbr =
+ AARCH64_FEATURE (CMPBR);
static const aarch64_feature_set aarch64_feature_memtag =
AARCH64_FEATURE (MEMTAG);
static const aarch64_feature_set aarch64_feature_bfloat16 =
@@ -2897,6 +2912,7 @@ static const aarch64_feature_set aarch64_feature_sve2p1_sme2p1 =
#define SB &aarch64_feature_sb
#define PREDRES &aarch64_feature_predres
#define PREDRES2 &aarch64_feature_predres2
+#define CMPBR &aarch64_feature_cmpbr
#define MEMTAG &aarch64_feature_memtag
#define TME &aarch64_feature_tme
#define SVE2 &aarch64_feature_sve2
@@ -3022,6 +3038,8 @@ static const aarch64_feature_set aarch64_feature_sve2p1_sme2p1 =
{ NAME, OPCODE, MASK, CLASS, 0, SB, OPS, QUALS, FLAGS, 0, 0, NULL }
#define PREDRES_INSN(NAME,OPCODE,MASK,CLASS,OPS,QUALS,FLAGS) \
{ NAME, OPCODE, MASK, CLASS, 0, PREDRES, OPS, QUALS, FLAGS, 0, 0, NULL }
+#define CMPBR_INSN(NAME,OPCODE,MASK,CLASS,OPS,QUALS,FLAGS) \
+ { NAME, OPCODE, MASK, CLASS, 0, CMPBR, OPS, QUALS, FLAGS, 0, 0, NULL }
#define MEMTAG_INSN(NAME,OPCODE,MASK,CLASS,OPS,QUALS,FLAGS) \
{ NAME, OPCODE, MASK, CLASS, 0, MEMTAG, OPS, QUALS, FLAGS, 0, 0, NULL }
#define _TME_INSN(NAME,OPCODE,MASK,CLASS,OP,OPS,QUALS,FLAGS) \
@@ -3965,6 +3983,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. */
+ CMPBR_INSN ("cbgt", 0x74000000, 0x7fe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF | F_HAS_ALIAS),
+ CMPBR_INSN ("cblt", 0x74000000, 0x7fe0c000, compbranch, OP3 (Rm, Rt, ADDR_PCREL9), QL_R2NIL, F_SF | F_ALIAS | F_PSEUDO),
+ CMPBR_INSN ("cbge", 0x74200000, 0x7fe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF | F_HAS_ALIAS),
+ CMPBR_INSN ("cble", 0x74200000, 0x7fe0c000, compbranch, OP3 (Rm, Rt, ADDR_PCREL9), QL_R2NIL, F_SF | F_ALIAS | F_PSEUDO),
+ CMPBR_INSN ("cbhi", 0x74400000, 0x7fe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF | F_HAS_ALIAS),
+ CMPBR_INSN ("cblo", 0x74400000, 0x7fe0c000, compbranch, OP3 (Rm, Rt, ADDR_PCREL9), QL_R2NIL, F_SF | F_ALIAS | F_PSEUDO),
+ CMPBR_INSN ("cbhs", 0x74600000, 0x7fe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF | F_HAS_ALIAS),
+ CMPBR_INSN ("cbls", 0x74600000, 0x7fe0c000, compbranch, OP3 (Rm, Rt, ADDR_PCREL9), QL_R2NIL, F_SF | F_ALIAS | F_PSEUDO),
+ CMPBR_INSN ("cbeq", 0x74c00000, 0x7fe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF),
+ CMPBR_INSN ("cbne", 0x74e00000, 0x7fe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_R2NIL, F_SF),
+ /* Compare register with immediate and branch. */
+ CMPBR_INSN ("cbgt", 0x75000000, 0x7fe04000, compbranch, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_HAS_ALIAS),
+ CMPBR_INSN ("cbge", 0x75000000, 0x7fe04000, compbranch, OP3 (Rt, IMMP1_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_ALIAS | F_PSEUDO),
+ CMPBR_INSN ("cblt", 0x75200000, 0x7fe04000, compbranch, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_HAS_ALIAS),
+ CMPBR_INSN ("cble", 0x75200000, 0x7fe04000, compbranch, OP3 (Rt, IMMS1_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_ALIAS | F_PSEUDO),
+ CMPBR_INSN ("cbhi", 0x75400000, 0x7fe04000, compbranch, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_HAS_ALIAS),
+ CMPBR_INSN ("cbhs", 0x75400000, 0x7fe04000, compbranch, OP3 (Rt, IMMP1_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_ALIAS | F_PSEUDO),
+ CMPBR_INSN ("cblo", 0x75600000, 0x7fe04000, compbranch, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_HAS_ALIAS),
+ CMPBR_INSN ("cbls", 0x75600000, 0x7fe04000, compbranch, OP3 (Rt, IMMS1_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF | F_ALIAS | F_PSEUDO),
+ CMPBR_INSN ("cbeq", 0x75c00000, 0x7fe04000, compbranch, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF),
+ CMPBR_INSN ("cbne", 0x75e00000, 0x7fe04000, compbranch, OP3 (Rt, IMM_2, ADDR_PCREL9), QL_R_IMM_PCREL, F_SF),
+ /* Compare bytes and branch. */
+ CMPBR_INSN ("cbbgt", 0x74008000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
+ CMPBR_INSN ("cbblt", 0x74008000, 0xffe0c000, compbranch, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS | F_PSEUDO),
+ CMPBR_INSN ("cbbge", 0x74208000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
+ CMPBR_INSN ("cbble", 0x74208000, 0xffe0c000, compbranch, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS | F_PSEUDO),
+ CMPBR_INSN ("cbbhi", 0x74408000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
+ CMPBR_INSN ("cbblo", 0x74408000, 0xffe0c000, compbranch, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS | F_PSEUDO),
+ CMPBR_INSN ("cbbhs", 0x74608000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
+ CMPBR_INSN ("cbbls", 0x74608000, 0xffe0c000, compbranch, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS | F_PSEUDO),
+ CMPBR_INSN ("cbbeq", 0x74c08000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, 0),
+ CMPBR_INSN ("cbbne", 0x74e08000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, 0),
+ /* Compare halfwords and branch. */
+ CMPBR_INSN ("cbhgt", 0x7400c000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
+ CMPBR_INSN ("cbhlt", 0x7400c000, 0xffe0c000, compbranch, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS | F_PSEUDO),
+ CMPBR_INSN ("cbhge", 0x7420c000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
+ CMPBR_INSN ("cbhle", 0x7420c000, 0xffe0c000, compbranch, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS | F_PSEUDO),
+ CMPBR_INSN ("cbhhi", 0x7440c000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
+ CMPBR_INSN ("cbhlo", 0x7440c000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS | F_PSEUDO),
+ CMPBR_INSN ("cbhhs", 0x7460c000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, F_HAS_ALIAS),
+ CMPBR_INSN ("cbhls", 0x7460c000, 0xffe0c000, compbranch, OP3 (Rm, Rt, ADDR_PCREL9), QL_W2_PCREL, F_ALIAS | F_PSEUDO),
+ CMPBR_INSN ("cbheq", 0x74c0c000, 0xffe0c000, compbranch, OP3 (Rt, Rm, ADDR_PCREL9), QL_W2_PCREL, 0),
+ CMPBR_INSN ("cbhne", 0x74e0c000, 0xffe0c000, compbranch, 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 +7188,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 +7234,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, \