aarch64: Add support for (M)ADDPT and (M)SUBPT instructions

The following instructions are added in this patch:

 - ADDPT and SUBPT - Add/Subtract checked pointer
 - MADDPT and MSUBPT - Multiply Add/Subtract checked pointer

These instructions are part of Checked Pointer Arithmetic extension.
This patch adds assembler and disassembler support for these instructions
with relevant checks. Tests are included as well.

A new flag "+cpa" added to documentation. This flag enables CPA extension.

Regression tested on the aarch64-none-linux-gnu target and no regressions
have been found.
This commit is contained in:
Yury Khrustalev 2024-02-21 12:52:23 +00:00 committed by Nick Clifton
parent ee0fa66270
commit 4792a423d2
16 changed files with 313 additions and 1 deletions

View file

@ -3748,6 +3748,41 @@ parse_shifter_operand (char **str, aarch64_opnd_info *operand,
return parse_shifter_operand_imm (str, operand, mode);
}
static bool
parse_reg_lsl_shifter_operand (char **str, aarch64_opnd_info *operand)
{
aarch64_opnd_qualifier_t qualifier;
const reg_entry *reg = aarch64_reg_parse_32_64 (str, &qualifier);
if (reg)
{
if (!aarch64_check_reg_type (reg, REG_TYPE_R_ZR))
{
set_expected_reg_error (REG_TYPE_R_ZR, reg, 0);
return false;
}
operand->reg.regno = reg->number;
operand->qualifier = qualifier;
/* Accept optional LSL shift operation on register. */
if (!skip_past_comma (str))
return true;
if (!parse_shift (str, operand, SHIFTED_LSL))
return false;
return true;
}
else
{
set_syntax_error
(_("integer register expected in the shifted operand "
"register"));
return false;
}
}
/* Return TRUE on success; return FALSE otherwise. */
static bool
@ -6593,6 +6628,17 @@ parse_operands (char *str, const aarch64_opcode *opcode)
}
break;
case AARCH64_OPND_Rm_LSL:
po_misc_or_fail (parse_reg_lsl_shifter_operand (&str, info));
if (!info->shifter.operator_present)
{
/* Default to LSL #0 if not present. */
gas_assert (info->shifter.kind == AARCH64_MOD_NONE);
info->shifter.kind = AARCH64_MOD_LSL;
info->shifter.amount = 0;
}
break;
case AARCH64_OPND_Fd:
case AARCH64_OPND_Fn:
case AARCH64_OPND_Fm:
@ -10429,6 +10475,7 @@ static const struct aarch64_option_cpu_value_table aarch64_features[] = {
{"sme2p1", AARCH64_FEATURE (SME2p1), AARCH64_FEATURE (SME2)},
{"sve2p1", AARCH64_FEATURE (SVE2p1), AARCH64_FEATURE (SVE2)},
{"rcpc3", AARCH64_FEATURE (RCPC3), AARCH64_FEATURE (RCPC2)},
{"cpa", AARCH64_FEATURE (CPA), AARCH64_NO_FEATURES},
{NULL, AARCH64_NO_FEATURES, AARCH64_NO_FEATURES},
};

View file

@ -289,6 +289,8 @@ automatically cause those extensions to be disabled.
@tab Enable @code{wfet} and @code{wfit} instructions.
@item @code{xs} @tab
@tab Enable the XS memory attribute extension.
@item @code{cpa} @tab
@tab Enable the Checked Pointer Arithmetic extension.
@end multitable
@multitable @columnfractions .20 .80

View file

@ -0,0 +1,4 @@
#name: Incorrect input test for CPA instructions ((M)ADDPT and (M)SUBPT).
#as: -march=armv8-a+cpa
#source: cpa-addsub-bad.s
#error_output: cpa-addsub-bad.l

View file

@ -0,0 +1,50 @@
.*: Assembler messages:
.*: Error: operand mismatch -- `addpt w5,w8,w0'
.*: Info:\s+did you mean this\?
.*: Info:\s+addpt x5, x8, x0
.*: Error: only 'LSL' shift is permitted at operand 3 -- `addpt x5,x8,x0,asr#6'
.*: Error: shift amount out of range 0 to 7 at operand 3 -- `addpt x5,x8,x0,lsl#9'
.*: Error: expected an integer or zero register at operand 3 -- `addpt x5,x8,sp,lsl#5'
.*: Error: expected an integer or stack pointer register at operand 1 -- `addpt xzr,x8,x0,lsl#3'
.*: Error: operand mismatch -- `subpt w5,w8,w0'
.*: Info:\s+did you mean this\?
.*: Info:\s+subpt x5, x8, x0
.*: Error: only 'LSL' shift is permitted at operand 3 -- `subpt x5,x8,x0,asr#6'
.*: Error: shift amount out of range 0 to 7 at operand 3 -- `subpt x5,x8,x0,lsl#9'
.*: Error: expected an integer or zero register at operand 3 -- `subpt x5,x8,sp,lsl#5'
.*: Error: expected an integer or stack pointer register at operand 1 -- `subpt xzr,x8,x0,lsl#3'
.*: Error: operand mismatch -- `maddpt w1,x2,x3,x4'
.*: Info:\s+did you mean this\?
.*: Info:\s+maddpt x1, x2, x3, x4
.*: Error: operand mismatch -- `maddpt x1,w2,x3,x4'
.*: Info:\s+did you mean this\?
.*: Info:\s+maddpt x1, x2, x3, x4
.*: Error: operand mismatch -- `maddpt x1,x2,w3,x4'
.*: Info:\s+did you mean this\?
.*: Info:\s+maddpt x1, x2, x3, x4
.*: Error: operand mismatch -- `maddpt x1,x2,x3,w4'
.*: Info:\s+did you mean this\?
.*: Info:\s+maddpt x1, x2, x3, x4
.*: Error: expected an integer or zero register at operand 1 -- `maddpt sp,x2,x3,x4'
.*: Error: expected an integer or zero register at operand 2 -- `maddpt x1,sp,x3,x4'
.*: Error: expected an integer or zero register at operand 3 -- `maddpt x1,x2,sp,x4'
.*: Error: expected an integer or zero register at operand 4 -- `maddpt x1,x2,x3,sp'
.*: Error: operand mismatch -- `msubpt w1,x2,x3,x4'
.*: Info:\s+did you mean this\?
.*: Info:\s+msubpt x1, x2, x3, x4
.*: Error: operand mismatch -- `msubpt x1,w2,x3,x4'
.*: Info:\s+did you mean this\?
.*: Info:\s+msubpt x1, x2, x3, x4
.*: Error: operand mismatch -- `msubpt x1,x2,w3,x4'
.*: Info:\s+did you mean this\?
.*: Info:\s+msubpt x1, x2, x3, x4
.*: Error: operand mismatch -- `msubpt x1,x2,x3,w4'
.*: Info:\s+did you mean this\?
.*: Info:\s+msubpt x1, x2, x3, x4
.*: Error: expected an integer or zero register at operand 1 -- `msubpt sp,x2,x3,x4'
.*: Error: expected an integer or zero register at operand 2 -- `msubpt x1,sp,x3,x4'
.*: Error: expected an integer or zero register at operand 3 -- `msubpt x1,x2,sp,x4'
.*: Error: expected an integer or zero register at operand 4 -- `msubpt x1,x2,x3,sp'

View file

@ -0,0 +1,29 @@
addpt w5, w8, w0
addpt x5, x8, x0, asr #6
addpt x5, x8, x0, lsl #9
addpt x5, x8, sp, lsl #5
addpt xzr, x8, x0, lsl #3
subpt w5, w8, w0
subpt x5, x8, x0, asr #6
subpt x5, x8, x0, lsl #9
subpt x5, x8, sp, lsl #5
subpt xzr, x8, x0, lsl #3
maddpt w1, x2, x3, x4
maddpt x1, w2, x3, x4
maddpt x1, x2, w3, x4
maddpt x1, x2, x3, w4
maddpt sp, x2, x3, x4
maddpt x1, sp, x3, x4
maddpt x1, x2, sp, x4
maddpt x1, x2, x3, sp
msubpt w1, x2, x3, x4
msubpt x1, w2, x3, x4
msubpt x1, x2, w3, x4
msubpt x1, x2, x3, w4
msubpt sp, x2, x3, x4
msubpt x1, sp, x3, x4
msubpt x1, x2, sp, x4
msubpt x1, x2, x3, sp

View file

@ -0,0 +1,5 @@
#name: Negative test for CPA instructions ((M)ADDPT and (M)SUBPT).
#as: -march=armv8-a
#as: -march=armv9-a
#source: cpa-addsub.s
#error_output: cpa-addsub-neg.l

View file

@ -0,0 +1,27 @@
.*: Assembler messages:
.*: Error: selected processor does not support `addpt x0,x0,x0'
.*: Error: selected processor does not support `addpt sp,x0,x0'
.*: Error: selected processor does not support `addpt x0,sp,x0'
.*: Error: selected processor does not support `addpt x0,x0,xzr'
.*: Error: selected processor does not support `addpt x0,x0,x0,lsl#0'
.*: Error: selected processor does not support `addpt x0,x0,x0,lsl#7'
.*: Error: selected processor does not support `addpt x8,x13,x29,lsl#5'
.*: Error: selected processor does not support `subpt x0,x0,x0'
.*: Error: selected processor does not support `subpt sp,x0,x0'
.*: Error: selected processor does not support `subpt x0,sp,x0'
.*: Error: selected processor does not support `subpt x0,x0,xzr'
.*: Error: selected processor does not support `subpt x0,x0,x0,lsl#0'
.*: Error: selected processor does not support `subpt x0,x0,x0,lsl#7'
.*: Error: selected processor does not support `subpt x1,x10,x22,lsl#2'
.*: Error: selected processor does not support `maddpt x0,x0,x0,x0'
.*: Error: selected processor does not support `maddpt xzr,x0,x0,x0'
.*: Error: selected processor does not support `maddpt x0,xzr,x0,x0'
.*: Error: selected processor does not support `maddpt x0,x0,xzr,x0'
.*: Error: selected processor does not support `maddpt x0,x0,x0,xzr'
.*: Error: selected processor does not support `maddpt x19,x10,x1,x28'
.*: Error: selected processor does not support `msubpt x0,x0,x0,x0'
.*: Error: selected processor does not support `msubpt xzr,x0,x0,x0'
.*: Error: selected processor does not support `msubpt x0,xzr,x0,x0'
.*: Error: selected processor does not support `msubpt x0,x0,xzr,x0'
.*: Error: selected processor does not support `msubpt x0,x0,x0,xzr'
.*: Error: selected processor does not support `msubpt x4,x13,x9,x21'

View file

@ -0,0 +1,39 @@
#name: Tests for CPA instructions ((M)ADDPT and (M)SUBPT).
#as: -march=armv8-a+cpa
#objdump: -dr
[^:]+: file format .*
[^:]+:
[^:]+:
.*: 9a002000 addpt x0, x0, x0
.*: 9a00201f addpt sp, x0, x0
.*: 9a0023e0 addpt x0, sp, x0
.*: 9a1f2000 addpt x0, x0, xzr
.*: 9a002000 addpt x0, x0, x0
.*: 9a003c00 addpt x0, x0, x0, lsl #7
.*: 9a1d35a8 addpt x8, x13, x29, lsl #5
.*: da002000 subpt x0, x0, x0
.*: da00201f subpt sp, x0, x0
.*: da0023e0 subpt x0, sp, x0
.*: da1f2000 subpt x0, x0, xzr
.*: da002000 subpt x0, x0, x0
.*: da003c00 subpt x0, x0, x0, lsl #7
.*: da162941 subpt x1, x10, x22, lsl #2
.*: 9b600000 maddpt x0, x0, x0, x0
.*: 9b60001f maddpt xzr, x0, x0, x0
.*: 9b6003e0 maddpt x0, xzr, x0, x0
.*: 9b7f0000 maddpt x0, x0, xzr, x0
.*: 9b607c00 maddpt x0, x0, x0, xzr
.*: 9b617153 maddpt x19, x10, x1, x28
.*: 9b608000 msubpt x0, x0, x0, x0
.*: 9b60801f msubpt xzr, x0, x0, x0
.*: 9b6083e0 msubpt x0, xzr, x0, x0
.*: 9b7f8000 msubpt x0, x0, xzr, x0
.*: 9b60fc00 msubpt x0, x0, x0, xzr
.*: 9b69d5a4 msubpt x4, x13, x9, x21

View file

@ -0,0 +1,29 @@
addpt x0, x0, x0
addpt sp, x0, x0
addpt x0, sp, x0
addpt x0, x0, xzr
addpt x0, x0, x0, lsl #0
addpt x0, x0, x0, lsl #7
addpt x8, x13, x29, lsl #5
subpt x0, x0, x0
subpt sp, x0, x0
subpt x0, sp, x0
subpt x0, x0, xzr
subpt x0, x0, x0, lsl #0
subpt x0, x0, x0, lsl #7
subpt x1, x10, x22, lsl #2
maddpt x0, x0, x0, x0
maddpt xzr, x0, x0, x0
maddpt x0, xzr, x0, x0
maddpt x0, x0, xzr, x0
maddpt x0, x0, x0, xzr
maddpt x19, x10, x1, x28
msubpt x0, x0, x0, x0
msubpt xzr, x0, x0, x0
msubpt x0, xzr, x0, x0
msubpt x0, x0, xzr, x0
msubpt x0, x0, x0, xzr
msubpt x4, x13, x9, x21

View file

@ -228,6 +228,8 @@ enum aarch64_feature_bit {
AARCH64_FEATURE_SVE2p1,
/* RCPC3 instructions. */
AARCH64_FEATURE_RCPC3,
/* Checked Pointer Arithmetic instructions. */
AARCH64_FEATURE_CPA,
AARCH64_NUM_FEATURES
};
@ -490,6 +492,7 @@ enum aarch64_opnd
AARCH64_OPND_PAIRREG_OR_XZR, /* Paired register operand, optionally xzr. */
AARCH64_OPND_Rm_EXT, /* Integer Rm extended. */
AARCH64_OPND_Rm_SFT, /* Integer Rm shifted. */
AARCH64_OPND_Rm_LSL, /* Integer Rm shifted (LSL-only). */
AARCH64_OPND_Fd, /* Floating-point Fd. */
AARCH64_OPND_Fn, /* Floating-point Fn. */

View file

@ -1020,6 +1020,21 @@ aarch64_ins_reg_shifted (const aarch64_operand *self ATTRIBUTE_UNUSED,
return true;
}
/* Encode the LSL-shifted register operand for e.g.
ADDPT <Xd|SP>, <Xn|SP>, <Xm>{, LSL #<amount>}. */
bool
aarch64_ins_reg_lsl_shifted (const aarch64_operand *self ATTRIBUTE_UNUSED,
const aarch64_opnd_info *info, aarch64_insn *code,
const aarch64_inst *inst ATTRIBUTE_UNUSED,
aarch64_operand_error *errors ATTRIBUTE_UNUSED)
{
/* Rm */
insert_field (FLD_Rm, code, info->reg.regno, 0);
/* imm3 */
insert_field (FLD_imm3_10, code, info->shifter.amount, 0);
return true;
}
/* Encode an SVE address [<base>, #<simm4>*<factor>, MUL VL],
where <simm4> is a 4-bit signed value and where <factor> is 1 plus
SELF's operand-dependent value. fields[0] specifies the field that

View file

@ -75,6 +75,7 @@ AARCH64_DECL_OPD_INSERTER (ins_hint);
AARCH64_DECL_OPD_INSERTER (ins_prfop);
AARCH64_DECL_OPD_INSERTER (ins_reg_extended);
AARCH64_DECL_OPD_INSERTER (ins_reg_shifted);
AARCH64_DECL_OPD_INSERTER (ins_reg_lsl_shifted);
AARCH64_DECL_OPD_INSERTER (ins_sve_addr_ri_s4);
AARCH64_DECL_OPD_INSERTER (ins_sve_addr_ri_s4xvl);
AARCH64_DECL_OPD_INSERTER (ins_sve_addr_ri_s6xvl);

View file

@ -1526,6 +1526,23 @@ aarch64_ext_reg_shifted (const aarch64_operand *self ATTRIBUTE_UNUSED,
return true;
}
/* Decode the LSL-shifted register operand for e.g.
ADDPT <Xd|SP>, <Xn|SP>, <Xm>{, LSL #<amount>}. */
bool
aarch64_ext_reg_lsl_shifted (const aarch64_operand *self ATTRIBUTE_UNUSED,
aarch64_opnd_info *info,
aarch64_insn code,
const aarch64_inst *inst ATTRIBUTE_UNUSED,
aarch64_operand_error *errors ATTRIBUTE_UNUSED)
{
/* Rm */
info->reg.regno = extract_field (FLD_Rm, code, 0);
/* imm3 */
info->shifter.kind = AARCH64_MOD_LSL;
info->shifter.amount = extract_field (FLD_imm3_10, code, 0);
return true;
}
/* Decode an SVE address [<base>, #<offset>*<factor>, MUL VL],
where <offset> is given by the OFFSET parameter and where <factor> is
1 plus SELF's operand-dependent value. fields[0] specifies the field

View file

@ -99,6 +99,7 @@ AARCH64_DECL_OPD_EXTRACTOR (ext_hint);
AARCH64_DECL_OPD_EXTRACTOR (ext_prfop);
AARCH64_DECL_OPD_EXTRACTOR (ext_reg_extended);
AARCH64_DECL_OPD_EXTRACTOR (ext_reg_shifted);
AARCH64_DECL_OPD_EXTRACTOR (ext_reg_lsl_shifted);
AARCH64_DECL_OPD_EXTRACTOR (ext_sve_addr_ri_s4);
AARCH64_DECL_OPD_EXTRACTOR (ext_sve_addr_ri_s4xvl);
AARCH64_DECL_OPD_EXTRACTOR (ext_sve_addr_ri_s6xvl);

View file

@ -3270,6 +3270,17 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
}
break;
case AARCH64_OPND_Rm_LSL:
/* We expect here that opnd->shifter.kind != AARCH64_MOD_LSL
because the parser already restricts the type of shift to LSL only,
so another check of shift kind would be redundant. */
if (!value_in_range_p (opnd->shifter.amount, 0, 7))
{
set_sft_amount_out_of_range_error (mismatch_detail, idx, 0, 7);
return 0;
}
break;
default:
break;
}
@ -4005,6 +4016,20 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
style_imm (styler, "#%" PRIi64, opnd->shifter.amount));
break;
case AARCH64_OPND_Rm_LSL:
assert (opnd->qualifier == AARCH64_OPND_QLF_X);
assert (opnd->shifter.kind == AARCH64_MOD_LSL);
if (opnd->shifter.amount == 0)
snprintf (buf, size, "%s",
style_reg (styler, get_int_reg_name (opnd->reg.regno,
opnd->qualifier, 0)));
else
snprintf (buf, size, "%s, %s %s",
style_reg (styler, get_int_reg_name (opnd->reg.regno, opnd->qualifier, 0)),
style_sub_mnem (styler, aarch64_operand_modifiers[opnd->shifter.kind].name),
style_imm (styler, "#%" PRIi64, opnd->shifter.amount));
break;
case AARCH64_OPND_Fd:
case AARCH64_OPND_Fn:
case AARCH64_OPND_Fm:

View file

@ -240,6 +240,12 @@
QLF4(X,X,X,X), \
}
/* e.g. MADDPT <Xd>, <Xn>, <Xm>, <Xa>. */
#define QL_I4SAMEX \
{ \
QLF4(X,X,X,X), \
}
/* e.g. SMADDL <Xd>, <Wn>, <Wm>, <Xa>. */
#define QL_I3SAMEL \
{ \
@ -2649,7 +2655,8 @@ static const aarch64_feature_set aarch64_feature_sve2p1 =
AARCH64_FEATURE (SVE2p1);
static const aarch64_feature_set aarch64_feature_rcpc3 =
AARCH64_FEATURE (RCPC3);
static const aarch64_feature_set aarch64_feature_cpa =
AARCH64_FEATURE (CPA);
#define CORE &aarch64_feature_v8
#define FP &aarch64_feature_fp
@ -2716,6 +2723,7 @@ static const aarch64_feature_set aarch64_feature_rcpc3 =
#define SME2p1 &aarch64_feature_sme2p1
#define SVE2p1 &aarch64_feature_sve2p1
#define RCPC3 &aarch64_feature_rcpc3
#define CPA &aarch64_feature_cpa
#define CORE_INSN(NAME,OPCODE,MASK,CLASS,OP,OPS,QUALS,FLAGS) \
{ NAME, OPCODE, MASK, CLASS, OP, CORE, OPS, QUALS, FLAGS, 0, 0, NULL }
@ -2888,6 +2896,8 @@ static const aarch64_feature_set aarch64_feature_rcpc3 =
{ NAME, OPCODE, MASK, the, 0, D128_THE, OPS, QUALS, FLAGS, 0, 0, NULL }
#define RCPC3_INSN(NAME,OPCODE,MASK,CLASS,OPS,QUALS,FLAGS) \
{ NAME, OPCODE, MASK, CLASS, 0, RCPC3, OPS, QUALS, FLAGS, 0, 0, NULL }
#define CPA_INSN(NAME,OPCODE,MASK,CLASS,OPS,QUALS) \
{ NAME, OPCODE, MASK, CLASS, 0, CPA, OPS, QUALS, 0, 0, 0, NULL }
#define MOPS_CPY_OP1_OP2_PME_INSN(NAME, OPCODE, MASK, FLAGS, CONSTRAINTS) \
MOPS_INSN (NAME, OPCODE, MASK, 0, \
@ -6392,6 +6402,12 @@ const struct aarch64_opcode aarch64_opcode_table[] =
SVE2p1_INSNC("st3q",0xe4a00000, 0xffe0e000, sve_misc, 0, OP3 (SME_Zt3, SVE_Pg3, SVE_ADDR_RR_LSL4), OP_SVE_QUU, 0, C_SCAN_MOVPRFX, 0),
SVE2p1_INSNC("st4q",0xe4e00000, 0xffe0e000, sve_misc, 0, OP3 (SME_Zt4, SVE_Pg3, SVE_ADDR_RR_LSL4), OP_SVE_QUU, 0, C_SCAN_MOVPRFX, 0),
/* Checked Pointer Arithmetic Instructions. */
CPA_INSN ("addpt", 0x9a002000, 0xffe0e000, aarch64_misc, OP3 (Rd_SP, Rn_SP, Rm_LSL), QL_I3SAMEX),
CPA_INSN ("subpt", 0xda002000, 0xffe0e000, aarch64_misc, OP3 (Rd_SP, Rn_SP, Rm_LSL), QL_I3SAMEX),
CPA_INSN ("maddpt", 0x9b600000, 0xffe08000, aarch64_misc, OP4 (Rd, Rn, Rm, Ra), QL_I4SAMEX),
CPA_INSN ("msubpt", 0x9b608000, 0xffe08000, aarch64_misc, OP4 (Rd, Rn, Rm, Ra), QL_I4SAMEX),
{0, 0, 0, 0, 0, 0, {}, {}, 0, 0, 0, NULL},
};
@ -6440,6 +6456,8 @@ const struct aarch64_opcode aarch64_opcode_table[] =
"an integer register with optional extension") \
Y(MODIFIED_REG, reg_shifted, "Rm_SFT", 0, F(), \
"an integer register with optional shift") \
Y(MODIFIED_REG, reg_lsl_shifted, "Rm_LSL", 0, F(), \
"an integer register with optional LSL shift") \
Y(FP_REG, regno, "Fd", 0, F(FLD_Rd), "a floating-point register") \
Y(FP_REG, regno, "Fn", 0, F(FLD_Rn), "a floating-point register") \
Y(FP_REG, regno, "Fm", 0, F(FLD_Rm), "a floating-point register") \