[PATCH 1/2] aarch64: Add support for FEAT_LSCP.
Alice Carlotti
alice.carlotti@arm.com
Thu Dec 4 18:06:19 GMT 2025
On Wed, Nov 19, 2025 at 05:42:43PM +0000, richard.ball@arm.com wrote:
> From: Richard Ball <Richard.Ball@arm.com>
>
> This patch adds the new instructions from FEAT_LSCP.
> These instructions are LDAP, LDAPP and STLP.
> ---
> gas/config/tc-aarch64-ginsn.c | 4 +++-
> gas/config/tc-aarch64.c | 3 ++-
> gas/doc/c-aarch64.texi | 2 ++
> gas/testsuite/gas/aarch64/lscp.d | 20 ++++++++++++++++++++
> gas/testsuite/gas/aarch64/lscp.s | 13 +++++++++++++
> include/opcode/aarch64.h | 3 +++
> opcodes/aarch64-opc.c | 1 +
> opcodes/aarch64-tbl.h | 9 +++++++++
> 8 files changed, 53 insertions(+), 2 deletions(-)
> create mode 100644 gas/testsuite/gas/aarch64/lscp.d
> create mode 100644 gas/testsuite/gas/aarch64/lscp.s
>
> diff --git a/gas/config/tc-aarch64-ginsn.c b/gas/config/tc-aarch64-ginsn.c
> index 0201c68fa58..4eb492b9589 100644
> --- a/gas/config/tc-aarch64-ginsn.c
> +++ b/gas/config/tc-aarch64-ginsn.c
> @@ -227,7 +227,8 @@ aarch64_ginsn_ldstp (const symbolS *insn_end_sym)
> /* This function is for handling ldp / stp ops only. */
> gas_assert (opcode->iclass == ldstpair_indexed
> || opcode->iclass == ldstnapair_offs
> - || opcode->iclass == ldstpair_off);
> + || opcode->iclass == ldstpair_off
> + || opcode->iclass == ldstapair);
> gas_assert (aarch64_num_of_operands (opcode) == 3);
>
> opnd1 = &base->operands[0];
> @@ -894,6 +895,7 @@ aarch64_ginsn_new (const symbolS *insn_end_sym, enum ginsn_gen_mode gmode)
> case ldstpair_indexed:
> case ldstpair_off:
> case ldstnapair_offs:
> + case ldstapair:
> ginsn = aarch64_ginsn_ldstp (insn_end_sym);
> break;
>
> diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
> index 0ca54c3bd40..779529ea4e7 100644
> --- a/gas/config/tc-aarch64.c
> +++ b/gas/config/tc-aarch64.c
> @@ -10823,6 +10823,7 @@ static const struct aarch64_option_cpu_value_table aarch64_features[] = {
> {"sha3", AARCH64_FEATURE (SHA3), AARCH64_FEATURE (SHA2)},
> {"rng", AARCH64_FEATURE (RNG), AARCH64_NO_FEATURES},
> {"ssbs", AARCH64_FEATURE (SSBS), AARCH64_NO_FEATURES},
> + {"lscp", AARCH64_FEATURE (LSCP), AARCH64_NO_FEATURES},
> {"memtag", AARCH64_FEATURE (MEMTAG), AARCH64_NO_FEATURES},
> {"occmo", AARCH64_FEATURE (OCCMO), AARCH64_NO_FEATURES},
> {"cmpbr", AARCH64_FEATURE (CMPBR), AARCH64_NO_FEATURES},
> @@ -10860,7 +10861,7 @@ static const struct aarch64_option_cpu_value_table aarch64_features[] = {
> {"the", AARCH64_FEATURE (THE), AARCH64_NO_FEATURES},
> {"rasv2", AARCH64_FEATURE (RASv2), AARCH64_FEATURE (RAS)},
> {"ite", AARCH64_FEATURE (ITE), AARCH64_NO_FEATURES},
> - {"d128", AARCH64_FEATURE (D128), AARCH64_FEATURES (2, LSE128, ATS1A)},
> + {"d128", AARCH64_FEATURE (D128), AARCH64_FEATURES (3, LSE128, ATS1A, LSCP)},
I think this dependency hasn't been added to LLVM, and we probably shouldn't
have it here (although I intend to confirm this with the LLVM team).
> {"sve-b16b16", AARCH64_FEATURE (SVE_B16B16), AARCH64_NO_FEATURES},
> {"sve-bfscale", AARCH64_FEATURE (SVE_BFSCALE), AARCH64_NO_FEATURES},
> {"sme2p1", AARCH64_FEATURE (SME2p1), AARCH64_FEATURE (SME2)},
> diff --git a/gas/doc/c-aarch64.texi b/gas/doc/c-aarch64.texi
> index 9683d411ce9..caec5a5dc8a 100644
> --- a/gas/doc/c-aarch64.texi
> +++ b/gas/doc/c-aarch64.texi
> @@ -239,6 +239,8 @@ automatically cause those extensions to be disabled.
> @tab Enable Limited Ordering Regions extensions.
> @item @code{ls64} @tab
> @tab Enable the 64 Byte Loads/Stores extensions.
> +@item @code{lscp} @tab
> + @tab Enable the load acquire and store release pair extension.
> @item @code{lse} @tab
> @tab Enable Large System extensions.
> @item @code{lse128} @tab @code{lse}
> diff --git a/gas/testsuite/gas/aarch64/lscp.d b/gas/testsuite/gas/aarch64/lscp.d
> new file mode 100644
> index 00000000000..e94e0241d41
> --- /dev/null
> +++ b/gas/testsuite/gas/aarch64/lscp.d
> @@ -0,0 +1,20 @@
> +#name: LSCP instructions
> +#as: -march=armv8-a+lscp
> +#objdump: -dr
> +
> +.*: file format .*
> +
> +
> +Disassembly of section .*:
> +
> +.* <a>:
> +.*: d9415840 ldap x0, x1, \[x2\]
> +.*: d9415be0 ldap x0, x1, \[sp\]
> +
> +.* <b>:
> +.*: d9417840 ldapp x0, x1, \[x2\]
> +.*: d9417be0 ldapp x0, x1, \[sp\]
> +
> +.* <c>:
> +.*: d9015840 stlp x0, x1, \[x2\]
> +.*: d9015be0 stlp x0, x1, \[sp\]
> \ No newline at end of file
Please fix this missing newline.
> diff --git a/gas/testsuite/gas/aarch64/lscp.s b/gas/testsuite/gas/aarch64/lscp.s
> new file mode 100644
> index 00000000000..e0e74924058
> --- /dev/null
> +++ b/gas/testsuite/gas/aarch64/lscp.s
> @@ -0,0 +1,13 @@
> +/* Load acquire and store release pair instructions. */
> +
> +a:
> + ldap x0, x1, [x2]
> + ldap x0, x1, [sp]
> +
> +b:
> + ldapp x0, x1, [x2]
> + ldapp x0, x1, [sp]
> +
> +c:
> + stlp x0, x1, [x2]
> + stlp x0, x1, [sp]
These tests are insufficient to cover the full range of encodings. I would
suggest something like either:
stlp x0, x0, [x0]
stlp xzr, x0, [x0]
stlp x0, xzr, [x0]
stlp x0, x0, [sp]
or:
stlp x0, xzr, [x0]
stlp xzr, x0, [x0]
stlp x0, xzr, [sp]
The former is the normal pattern I use, although in this case it would require
the corresponding tests for ldap and ldapp to accept the unpredictable load
warning. The latter alternative would avoid the warnings in this test, but
then you'd need to write a second test to check the warnings, which probably
isn't necessary when you can just test them at the same time.
(To be clear, my primary issues with your tests are that there are some bits in
the encoding that can be either 0 or 1 depending on the operands, but you only
test one of those bit values, and you also don't test that xzr is accepted
instead of sp in the first two operands.)
> diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h
> index e65b61c3f9c..5d287199ee2 100644
> --- a/include/opcode/aarch64.h
> +++ b/include/opcode/aarch64.h
> @@ -263,6 +263,8 @@ enum aarch64_feature_bit {
> AARCH64_FEATURE_SME_TMOP,
> /* SME MOP4 instructions. */
> AARCH64_FEATURE_SME_MOP4,
> + /* LSCP instructions. */
> + AARCH64_FEATURE_LSCP,
>
> /* Virtual features. These are used to gate instructions that are enabled
> by either of two (or more) sets of command line flags. */
> @@ -1122,6 +1124,7 @@ enum aarch64_insn_class
> ldst_unpriv,
> ldst_unscaled,
> ldstexcl,
> + ldstapair,
I think you can use ldstpair_off instead of adding a new class.
You're also currently missing handling for these instructions in
warn_unpredictable_ldst, but switching to the existing instruction class would
fix that anyway.
Thanks,
Alice
> ldstnapair_offs,
> ldstpair_off,
> ldstpair_indexed,
> diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
> index b074765920e..79d15d2e3d5 100644
> --- a/opcodes/aarch64-opc.c
> +++ b/opcodes/aarch64-opc.c
> @@ -2248,6 +2248,7 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
> case ldst_unscaled:
> case ldstnapair_offs:
> case ldstpair_off:
> + case ldstapair:
> case ldst_unpriv:
> if (opnd->addr.writeback == 1)
> {
> diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h
> index 2fc69c27791..cbe4cda077f 100644
> --- a/opcodes/aarch64-tbl.h
> +++ b/opcodes/aarch64-tbl.h
> @@ -2917,6 +2917,8 @@ static const aarch64_feature_set aarch64_feature_v8r =
> AARCH64_FEATURE (V8R);
> static const aarch64_feature_set aarch64_feature_ls64 =
> AARCH64_FEATURE (LS64);
> +static const aarch64_feature_set aarch64_feature_lscp =
> + AARCH64_FEATURE (LSCP);
> static const aarch64_feature_set aarch64_feature_flagm =
> AARCH64_FEATURE (FLAGM);
> static const aarch64_feature_set aarch64_feature_xs =
> @@ -3111,6 +3113,7 @@ static const aarch64_feature_set aarch64_feature_sme_mop4_i16i64 =
> #define I8MM &aarch64_feature_i8mm
> #define ARMV8R &aarch64_feature_v8r
> #define LS64 &aarch64_feature_ls64
> +#define LSCP &aarch64_feature_lscp
> #define FLAGM &aarch64_feature_flagm
> #define XS &aarch64_feature_xs
> #define WFXT &aarch64_feature_wfxt
> @@ -3363,6 +3366,8 @@ static const aarch64_feature_set aarch64_feature_sme_mop4_i16i64 =
> { NAME, OPCODE, MASK, CLASS, 0, WFXT, OPS, QUALS, FLAGS, 0, 0, NULL }
> #define _LS64_INSN(NAME,OPCODE,MASK,CLASS,OPS,QUALS,FLAGS) \
> { NAME, OPCODE, MASK, CLASS, 0, LS64, OPS, QUALS, FLAGS, 0, 0, NULL }
> +#define _LSCP_INSN(NAME,OPCODE,MASK,CLASS,OPS,QUALS,FLAGS) \
> + { NAME, OPCODE, MASK, CLASS, 0, LSCP, OPS, QUALS, FLAGS, 0, 0, NULL }
> #define FLAGM_INSN(NAME,OPCODE,MASK,CLASS,OPS,QUALS,FLAGS) \
> { NAME, OPCODE, MASK, CLASS, 0, FLAGM, OPS, QUALS, FLAGS | F_INVALID_IMM_SYMS_1, 0, 0, NULL }
> #define MOPS_INSN(NAME, OPCODE, MASK, CLASS, OPS, QUALS, FLAGS, CONSTRAINTS, VERIFIER) \
> @@ -4658,6 +4663,10 @@ const struct aarch64_opcode aarch64_opcode_table[] =
> _LOR_INSN ("stllr", 0x889f7c00, 0xbfe08000, ldstexcl, OP2 (Rt, ADDR_SIMPLE), QL_R1NIL, F_GPRSIZE_IN_Q),
> _LOR_INSN ("stllrb", 0x089f7c00, 0xffe08000, ldstexcl, OP2 (Rt, ADDR_SIMPLE), QL_W1_LDST_EXC, 0),
> _LOR_INSN ("stllrh", 0x489f7c00, 0xbfe08000, ldstexcl, OP2 (Rt, ADDR_SIMPLE), QL_W1_LDST_EXC, 0),
> + /* Load acquire and store release pair. */
> + _LSCP_INSN ("ldap", 0xd9405800, 0xffe0fc00, ldstapair, OP3 (Rt, Rs, ADDR_SIMPLE), QL_X2NIL, 0),
> + _LSCP_INSN ("ldapp", 0xd9407800, 0xffe0fc00, ldstapair, OP3 (Rt, Rs, ADDR_SIMPLE), QL_X2NIL, 0),
> + _LSCP_INSN ("stlp", 0xd9005800, 0xffe0fc00, ldstapair, OP3 (Rt, Rs, ADDR_SIMPLE), QL_X2NIL, 0),
> /* Load/store no-allocate pair (offset). */
> CORE_INSN ("stnp", 0x28000000, 0x7fc00000, ldstnapair_offs, 0, OP3 (Rt, Rt2, ADDR_SIMM7), QL_LDST_PAIR_R, F_LDST_STORE | F_SF),
> CORE_INSN ("ldnp", 0x28400000, 0x7fc00000, ldstnapair_offs, 0, OP3 (Rt, Rt2, ADDR_SIMM7), QL_LDST_PAIR_R, F_LDST_LOAD | F_SF),
> --
> 2.34.1
>
More information about the Binutils
mailing list