diff --git a/gas/NEWS b/gas/NEWS index 2f82f45ec57..92d45777e82 100644 --- a/gas/NEWS +++ b/gas/NEWS @@ -43,6 +43,8 @@ * Add support for the AArch64 Lookup Table Extension (LUT). +* Add support for the AArch64 Lookup Table Extension v2 (LUTv2). + Changes in 2.42: * Add support for AMD znver5 processor. diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c index 885ea65b8eb..a82eb03593c 100644 --- a/gas/config/tc-aarch64.c +++ b/gas/config/tc-aarch64.c @@ -1365,6 +1365,11 @@ reg_type_mask (aarch64_reg_type reg_type) It returns PARSE_FAIL if the register list is invalid. + If HAS_QUALIFIER is true, the registers in the list must have qualifiers + or the list is invalid. + If HAS_QUALIFIER is false, the registers in the list must not have + qualifiers or the list is invalid. + The list contains one to four registers. Each register can be one of: .[] @@ -1376,7 +1381,8 @@ reg_type_mask (aarch64_reg_type reg_type) static int parse_vector_reg_list (char **ccp, aarch64_reg_type type, - struct vector_type_el *vectype) + struct vector_type_el *vectype, + bool has_qualifier) { char *str = *ccp; int nb_regs; @@ -1413,8 +1419,12 @@ parse_vector_reg_list (char **ccp, aarch64_reg_type type, str++; /* skip over '-' */ val_range = val; } - const reg_entry *reg = parse_typed_reg (&str, type, &typeinfo, - ptr_flags); + + const reg_entry *reg; + if (has_qualifier) + reg = parse_typed_reg (&str, type, &typeinfo, ptr_flags); + else + reg = parse_reg (&str); if (!reg) { set_first_syntax_error (_("invalid vector register in list")); @@ -3893,6 +3903,54 @@ parse_shifter_operand_reloc (char **str, aarch64_opnd_info *operand, return parse_shifter_operand (str, operand, mode); } +/* Parse a ZT0 vector with an optional bit index and a shifter operand. + zt0 + zt0[0, mul vl] + zt0[2, mul vl] + + We only support 'mul vl' as shifter operand and it is handled by + parse_shift. + + Return TRUE on success; otherwise return FALSE. */ + +static bool +parse_shifter_zt0_with_bit_index (char **str, + aarch64_opnd_info *operand, + enum parse_shift_mode mode) +{ + const reg_entry *reg = parse_reg (str); + if (reg == NULL) + return false; + + if (reg->type != REG_TYPE_ZT0) + return false; + + operand->reglane.regno = reg->number; + + if (!skip_past_char(str, '[')) + { + // It is not an error if the index is not present. Default index to 0. + operand->imm.value = 0; + return true; + } + + int64_t index; + if (!parse_index_expression (str, &index)) + return false; + operand->imm.value = index; + + if (!skip_past_comma(str)) + return true; + + if (!parse_shift(str, operand, mode)) + return false; + + if (!skip_past_char (str, ']')) + return false; + + return true; +} + /* Parse all forms of an address expression. Information is written to *OPERAND and/or inst.reloc. @@ -6860,10 +6918,26 @@ parse_operands (char *str, const aarch64_opcode *opcode) info->reglane.index = vectype.index; break; + case AARCH64_OPND_SME_Znx2_BIT_INDEX: + // A vector register list encoding a bit index. + reg_type = REG_TYPE_Z; + val = parse_vector_reg_list (&str, reg_type, &vectype, false); + if (val == PARSE_FAIL) + goto failure; + + if (! reg_list_valid_p (val, &info->reglist, reg_type)) + { + set_fatal_syntax_error (_("invalid register list")); + goto failure; + } + + break; + case AARCH64_OPND_SVE_ZnxN: case AARCH64_OPND_SVE_ZtxN: case AARCH64_OPND_SME_Zdnx2: case AARCH64_OPND_SME_Zdnx4: + case AARCH64_OPND_SME_Zdnx4_STRIDED: case AARCH64_OPND_SME_Zt2: case AARCH64_OPND_SME_Zt3: case AARCH64_OPND_SME_Zt4: @@ -6901,7 +6975,7 @@ parse_operands (char *str, const aarch64_opcode *opcode) } else { - val = parse_vector_reg_list (&str, reg_type, &vectype); + val = parse_vector_reg_list (&str, reg_type, &vectype, true); if (val == PARSE_FAIL) goto failure; @@ -7968,6 +8042,11 @@ parse_operands (char *str, const aarch64_opcode *opcode) info->imm.value = vectype.index; break; + case AARCH64_OPND_SME_ZT0_INDEX2_12: + po_misc_or_fail(parse_shifter_zt0_with_bit_index + (&str, info, SHIFTED_MUL_VL)); + break; + case AARCH64_OPND_SME_ZT0_LIST: if (*str != '{') { @@ -10597,6 +10676,7 @@ static const struct aarch64_option_cpu_value_table aarch64_features[] = { {"fp8", AARCH64_FEATURE (FP8), AARCH64_FEATURE (SIMD)}, {"lut", AARCH64_FEATURE (LUT), AARCH64_FEATURE (SIMD)}, {"brbe", AARCH64_FEATURE (BRBE), AARCH64_NO_FEATURES}, + {"sme-lutv2", AARCH64_FEATURE (SME_LUTv2), AARCH64_FEATURE (SME2)}, {NULL, AARCH64_NO_FEATURES, AARCH64_NO_FEATURES}, }; diff --git a/gas/doc/c-aarch64.texi b/gas/doc/c-aarch64.texi index b29da1f0e8f..41a8d7e4a44 100644 --- a/gas/doc/c-aarch64.texi +++ b/gas/doc/c-aarch64.texi @@ -269,6 +269,8 @@ automatically cause those extensions to be disabled. @tab Enable SME F64F64 Extension. @item @code{sme-i16i64} @tab @code{sme} @tab Enable SME I16I64 Extension. +@item @code{sme-lutv2} @tab + @tab Enable SME Lookup Table v2 (LUTv2) extension. @item @code{sme2} @tab @code{sme} @tab Enable SME2. @item @code{sme2p1} @tab @code{sme2} diff --git a/gas/testsuite/gas/aarch64/sme2-8-invalid.l b/gas/testsuite/gas/aarch64/sme2-8-invalid.l index aa393657c4b..aef9b1ad203 100644 --- a/gas/testsuite/gas/aarch64/sme2-8-invalid.l +++ b/gas/testsuite/gas/aarch64/sme2-8-invalid.l @@ -9,9 +9,9 @@ [^ :]+:[0-9]+: Error: expected '}' after ZT0 at operand 1 -- `zero {zt0' [^ :]+:[0-9]+: Error: expected '}' after ZT0 at operand 1 -- `zero {zt0\.b}' [^ :]+:[0-9]+: Error: expected '}' after ZT0 at operand 1 -- `zero {zt0,zt0}' -[^ :]+:[0-9]+: Error: expected a register at operand 1 -- `movt 0,zt0\[0\]' +[^ :]+:[0-9]+: Error: operand 1 must be an integer register -- `movt 0,zt0\[0\]' [^ :]+:[0-9]+: Error: expected a register at operand 2 -- `movt x0,0' -[^ :]+:[0-9]+: Error: missing register index at operand 1 -- `movt zt0,x0' +[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 2 -- `movt zt0,x0' [^ :]+:[0-9]+: Error: unexpected register type at operand 1 -- `movt za\[0\],x0' [^ :]+:[0-9]+: Error: unexpected register type at operand 1 -- `movt za0\[0\],x0' [^ :]+:[0-9]+: Error: bad expression at operand 1 -- `movt zt0\[#0\],x0' @@ -26,17 +26,17 @@ [^ :]+:[0-9]+: Error: register element index out of range 0 to 56 at operand 1 -- `movt zt0\[57\],x0' [^ :]+:[0-9]+: Error: register element index out of range 0 to 56 at operand 1 -- `movt zt0\[64\],x0' [^ :]+:[0-9]+: Error: register element index out of range 0 to 56 at operand 1 -- `movt zt0\[1<<32\],x0' -[^ :]+:[0-9]+: Error: missing register index at operand 1 -- `movt zt0\.b\[0\],x0' -[^ :]+:[0-9]+: Error: missing register index at operand 1 -- `movt zt0/z\[0\],x0' -[^ :]+:[0-9]+: Error: expected an integer or zero register at operand 2 -- `movt zt0\[0\],sp' +[^ :]+:[0-9]+: Error: comma expected between operands at operand 2 -- `movt zt0\.b\[0\],x0' +[^ :]+:[0-9]+: Error: comma expected between operands at operand 2 -- `movt zt0/z\[0\],x0' +[^ :]+:[0-9]+: Error: comma expected between operands at operand 2 -- `movt zt0\[0\],sp' [^ :]+:[0-9]+: Error: operand mismatch -- `movt zt0\[0\],w0' [^ :]+:[0-9]+: Info: did you mean this\? [^ :]+:[0-9]+: Info: movt zt0\[0\], x0 -[^ :]+:[0-9]+: Error: expected an integer or zero register at operand 2 -- `movt zt0\[0\],wsp' +[^ :]+:[0-9]+: Error: comma expected between operands at operand 2 -- `movt zt0\[0\],wsp' [^ :]+:[0-9]+: Error: operand mismatch -- `movt zt0\[0\],wzr' [^ :]+:[0-9]+: Info: did you mean this\? [^ :]+:[0-9]+: Info: movt zt0\[0\], xzr -[^ :]+:[0-9]+: Error: expected an integer or zero register at operand 2 -- `movt zt0\[0\],0' +[^ :]+:[0-9]+: Error: comma expected between operands at operand 2 -- `movt zt0\[0\],0' [^ :]+:[0-9]+: Error: expected a register at operand 1 -- `ldr 0,\[x0\]' [^ :]+:[0-9]+: Error: invalid addressing mode at operand 2 -- `ldr zt0,0' [^ :]+:[0-9]+: Error: operand 2 must be an address with base register \(no offset\) -- `ldr zt0,\[x0,#0\]' diff --git a/gas/testsuite/gas/aarch64/sme2-lutv2-bad.d b/gas/testsuite/gas/aarch64/sme2-lutv2-bad.d new file mode 100644 index 00000000000..0e6e2b77604 --- /dev/null +++ b/gas/testsuite/gas/aarch64/sme2-lutv2-bad.d @@ -0,0 +1,3 @@ +#as: -march=armv8-a+sme2 +#source: sme2-lutv2.s +#error_output: sme2-lutv2-bad.l \ No newline at end of file diff --git a/gas/testsuite/gas/aarch64/sme2-lutv2-bad.l b/gas/testsuite/gas/aarch64/sme2-lutv2-bad.l new file mode 100644 index 00000000000..78837221539 --- /dev/null +++ b/gas/testsuite/gas/aarch64/sme2-lutv2-bad.l @@ -0,0 +1,15 @@ +[^ :]+: Assembler messages: +.*: Error: selected processor does not support `movt zt0,z0' +.*: Error: selected processor does not support `movt zt0\[0,mul vl\],z31' +.*: Error: selected processor does not support `movt zt0\[3,mul vl\],z0' +.*: Error: selected processor does not support `movt zt0\[3,mul vl\],z31' +.*: Error: selected processor does not support `movt zt0\[2,mul vl\],z25' +.*: Error: selected processor does not support `luti4 {z0.b-z3.b},zt0,{z0-z1}' +.*: Error: selected processor does not support `luti4 {z28.b-z31.b},zt0,{z0-z1}' +.*: Error: selected processor does not support `luti4 {z0.b-z3.b},zt0,{z30-z31}' +.*: Error: selected processor does not support `luti4 {z20.b-z23.b},zt0,{z12-z13}' +.*: Error: selected processor does not support `luti4 {z0.b,z4.b,z8.b,z12.b},zt0,{z0-z1}' +.*: Error: selected processor does not support `luti4 {z19.b,z23.b,z27.b,z31.b},zt0,{z0-z1}' +.*: Error: selected processor does not support `luti4 {z0.b,z4.b,z8.b,z12.b},zt0,{z30-z31}' +.*: Error: selected processor does not support `luti4 {z17.b,z21.b,z25.b,z29.b},zt0,{z12-z13}' +.*: Error: selected processor does not support `luti4 {z20.b,z21.b,z22.b,z23.b},zt0,{z12-z13}' diff --git a/gas/testsuite/gas/aarch64/sme2-lutv2-illegal.d b/gas/testsuite/gas/aarch64/sme2-lutv2-illegal.d new file mode 100644 index 00000000000..401bbb72094 --- /dev/null +++ b/gas/testsuite/gas/aarch64/sme2-lutv2-illegal.d @@ -0,0 +1,3 @@ +#as: -march=armv8-a+sme2+sme2p1+sme-lutv2 +#source: sme2-lutv2-illegal.s +#error_output: sme2-lutv2-illegal.l \ No newline at end of file diff --git a/gas/testsuite/gas/aarch64/sme2-lutv2-illegal.l b/gas/testsuite/gas/aarch64/sme2-lutv2-illegal.l new file mode 100644 index 00000000000..4495a9adc52 --- /dev/null +++ b/gas/testsuite/gas/aarch64/sme2-lutv2-illegal.l @@ -0,0 +1,70 @@ +[^ :]+: Assembler messages: +[^ :]+:[0-9]+: Error: start register out of range at operand 3 -- `luti4 {z20.b-z23.h},zt0,{z13-z14}' +[^ :]+:[0-9]+: Error: type mismatch in vector register list at operand 1 -- `luti4 {z19.b,z23.b,z27.b,z31.h},zt0,{z13-z14}' +[^ :]+:[0-9]+: Error: unexpected register type at operand 1 -- `movt z3,zt0' +[^ :]+:[0-9]+: Error: unexpected register type at operand 1 -- `movt z3\[0\],zt0' +[^ :]+:[0-9]+: Error: operand 1 must be an integer register -- `movt zt1,z25' +[^ :]+:[0-9]+: Error: expected a vector register at operand 1 -- `luti4 zt0,\{z0.b-z3.b\},\{z0-z1\}' +[^ :]+:[0-9]+: Error: expected a register at operand 2 -- `luti4 \{z0.b-z3.b\},\{z0.b-z1.b\}\{z0-z1\}' +[^ :]+:[0-9]+: Error: syntax error in register list at operand 1 -- `luti4 \{\},zt0,\{z12-z13\}' +[^ :]+:[0-9]+: Error: invalid vector register in list at operand 3 -- `luti4 \{z20.b-z23.b\},zt0,\{\}' +[^ :]+:[0-9]+: Error: unexpected register type at operand 2 -- `luti4 \{z20.b-z23.b\},z3,\{z12-z13\}' +[^ :]+:[0-9]+: Error: start register out of range at operand 1 -- `luti4 \{z19.b-z22.b\},zt0,\{z12-z13\}' +[^ :]+:[0-9]+: Error: start register out of range at operand 3 -- `luti4 \{z20.b-z23.b\},zt0,\{z13-z14\}' +[^ :]+:[0-9]+: Error: expected a vector register at operand 1 -- `luti4 zt0,{z0.b,z4.b,z8.b,z12.b},{z0-z1}' +[^ :]+:[0-9]+: Error: expected a register at operand 2 -- `luti4 {z0.b,z4.b,z8.b,z12.b},{z0.b-z1.b}{z0-z1}' +[^ :]+:[0-9]+: Error: invalid vector register in list at operand 3 -- `luti4 {z19.b,z23.b,z27.b,z31.b},zt0,{}' +[^ :]+:[0-9]+: Error: unexpected register type at operand 2 -- `luti4 {z19.b,z23.b,z27.b,z31.b},z3,{z12-z13}' +[^ :]+:[0-9]+: Error: start register out of range at operand 3 -- `luti4 {z19.b,z23.b,z27.b,z31.b},zt0,{z13-z14}' +[^ :]+:[0-9]+: Error: operand mismatch -- `luti4 \{z20.s-z23.s\},zt0,\{z20-z21\}' +[^ :]+:[0-9]+: Info: did you mean this\? +[^ :]+:[0-9]+: Info: luti4 {z20.b-z23.b}, zt0, {z20-z21} +[^ :]+:[0-9]+: Error: operand mismatch -- `luti4 {z19.s,z23.s,z27.s,z31.s},zt0,{z20-z21}' +[^ :]+:[0-9]+: Info: did you mean this\? +[^ :]+:[0-9]+: Info: luti4 {z19.b, z23.b, z27.b, z31.b}, zt0, {z20-z21} +[^ :]+:[0-9]+: Error: comma expected between operands at operand 2 -- `movt zt0.b,z31' +[^ :]+:[0-9]+: Error: comma expected between operands at operand 2 -- `movt zt0.b\[0,mul vl\],z31' +[^ :]+:[0-9]+: Error: comma expected between operands at operand 2 -- `movt zt0' +[^ :]+:[0-9]+: Error: comma expected between operands at operand 2 -- `movt zt0\[1,mul vl\]' +[^ :]+:[0-9]+: Error: unexpected characters following instruction at operand 2 -- `movt zt0,z23,z31' +[^ :]+:[0-9]+: Error: unexpected characters following instruction at operand 2 -- `movt zt0\[1,mul vl\],z23,z31' +[^ :]+:[0-9]+: Error: comma expected between operands at operand 2 -- `luti4 \{z20.b-z23.b\}' +[^ :]+:[0-9]+: Error: comma expected between operands at operand 3 -- `luti4 \{z20.b-z23.b\},zt0' +[^ :]+:[0-9]+: Error: unexpected characters following instruction at operand 3 -- `luti4 \{z20.b-z23.b\},zt0,\{z12-z13\},\{z20-z21\}' +[^ :]+:[0-9]+: Error: comma expected between operands at operand 2 -- `luti4 {z19.b,z23.b,z27.b,z31.b}' +[^ :]+:[0-9]+: Error: comma expected between operands at operand 3 -- `luti4 {z19.b,z23.b,z27.b,z31.b},zt0' +[^ :]+:[0-9]+: Error: comma expected between operands at operand 3 -- `luti4 {z19.b,z23.b,z27.b,z31.b},zt0{z12-z13},{z20-z21}' +[^ :]+:[0-9]+: Error: operand 1 must be an integer register -- `movt zy0,z16' +[^ :]+:[0-9]+: Error: operand 1 must be an integer register -- `movt zt1,z16' +[^ :]+:[0-9]+: Error: operand 1 must be an integer register -- `movt zy0\[1,mul vl\],z16' +[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 2 -- `movt zt0,y16' +[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 2 -- `movt zt0\[1,mul vl\],y16' +[^ :]+:[0-9]+: Error: operand 1 must be a list of SVE vector registers -- `luti4 \{z20.b-y23.b\},zt0,\{z12-z13\}' +[^ :]+:[0-9]+: Error: unexpected character `x' in element size at operand 1 -- `luti4 \{z20.x-z23.b\},zt0,\{z12-z13\}' +[^ :]+:[0-9]+: Error: expected a register at operand 2 -- `luti4 \{z20.b-z23.b\},zy0,\{z12-z13\}' +[^ :]+:[0-9]+: Error: operand 1 must be a list of SVE vector registers -- `luti4 \{z20.b-y23.b\},zt0,\{y12-z13\}' +[^ :]+:[0-9]+: Error: operand 1 must be a list of SVE vector registers -- `luti4 {z19.b,z23.b,z27.b,y31.b},zt0,{z12-z13}' +[^ :]+:[0-9]+: Error: unexpected character `x' in element size at operand 1 -- `luti4 {z19.x,z23.b,z27.b,z31.b},zt0,{z12-z13}' +[^ :]+:[0-9]+: Error: expected a register at operand 2 -- `luti4 {z19.b,z23.b,z27.b,z31.b},zy0,{z12-z13}' +[^ :]+:[0-9]+: Error: invalid vector register in list at operand 3 -- `luti4 {z19.b,z23.b,z27.b,z31.b},zt0,{y12-z13}' +[^ :]+:[0-9]+: Error: missing type suffix at operand 1 -- `luti4 \{z20-z23.b\},zt0,\{z12-z13\}' +[^ :]+:[0-9]+: Error: type mismatch in vector register list at operand 1 -- `luti4 {z19.b,z23,z27.b,z31.b},zt0,{z12-z13}' +[^ :]+:[0-9]+: Error: operand 1 must be an integer register -- `movt zt,z25.b' +[^ :]+:[0-9]+: Error: end of vector register list not found at operand 3 -- `luti4 {z20.b-z23.b},zt0,{z12.b-z13.b}' +[^ :]+:[0-9]+: Error: end of vector register list not found at operand 3 -- `luti4 {z19.b,z23.b,z27.b,z31.b},zt0,{z12.b-z13.b}' +[^ :]+:[0-9]+: Error: operand 2 must be an SVE vector register -- `movt zt0,z25\[1\]' +[^ :]+:[0-9]+: Error: operand 2 must be an SVE vector register -- `movt zt0,z25\[1,mul vl\]' +[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 2 -- `movt zt0\[2,mul vl\],z32' +[^ :]+:[0-9]+: Error: register element index out of range 0 to 3 at operand 1 -- `movt zt0\[4,mul vl\],z25' +[^ :]+:[0-9]+: Error: register element index out of range 0 to 3 at operand 1 -- `movt zt0\[-1,mul vl\],z25' +[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 1 -- `luti4 {z32.b-z36.b},zt0,{z12-z13}' +[^ :]+:[0-9]+: Error: invalid vector register in list at operand 3 -- `luti4 {z20.b-z23.b},zt0,{z32-z33}' +[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 1 -- `luti4 {z32.b,z36.b,z40.b,z44.b},zt0,{z12-z13}' +[^ :]+:[0-9]+: Error: invalid vector register in list at operand 3 -- `luti4 {z19.b,z23.b,z27.b,z31.b},zt0,{z32-z33}' +[^ :]+:[0-9]+: Error: too many registers in vector register list at operand 1 -- `luti4 {z20.b-z24.b},zt0,{z12-z13}' +[^ :]+:[0-9]+: Error: expected a list of 4 registers at operand 1 -- `luti4 {z20.b-z22.b},zt0,{z12-z13}' +[^ :]+:[0-9]+: Error: invalid register stride at operand 1 -- `luti4 {z20.b-z23.b},zt0,{z12-z14}' +[^ :]+:[0-9]+: Error: invalid range in vector register list at operand 3 -- `luti4 {z20.b-z23.b},zt0,{z12-z12}' +[^ :]+:[0-9]+: Error: invalid register list at operand 1 -- `luti4 {z19.b,z24.b,z27.b,z31.b},zt0,{z12-z13}' +[^ :]+:[0-9]+: Error: invalid register list at operand 1 -- `luti4 {z19.b,z22.b,z27.b,z31.b},zt0,{z12-z13}' +[^ :]+:[0-9]+: Error: the register list must have a stride of 1 at operand 1 -- `luti4 {z19.b,z23.b,z27.b,z31.b},zt0,{z12-z14}' diff --git a/gas/testsuite/gas/aarch64/sme2-lutv2-illegal.s b/gas/testsuite/gas/aarch64/sme2-lutv2-illegal.s new file mode 100644 index 00000000000..4e36ef687fc --- /dev/null +++ b/gas/testsuite/gas/aarch64/sme2-lutv2-illegal.s @@ -0,0 +1,95 @@ + // Operand mismatch + luti4 { z20.b - z23.h }, zt0, { z13 - z14 } + luti4 { z19.b, z23.b, z27.b, z31.h }, zt0, { z13 - z14 } + + // Incorrect operands + movt z3, zt0 + movt z3[0], zt0 + movt zt1, z25 + + luti4 zt0, { z0.b - z3.b }, { z0 - z1 } + luti4 { z0.b - z3.b }, { z0.b - z1.b } { z0 - z1 } + luti4 { }, zt0, { z12 - z13 } + luti4 { z20.b - z23.b }, zt0, { } + luti4 { z20.b - z23.b }, z3, { z12 - z13 } + luti4 { z19.b - z22.b }, zt0, { z12 - z13 } + luti4 { z20.b - z23.b }, zt0, { z13 - z14 } + + luti4 zt0, { z0.b, z4.b, z8.b, z12.b }, { z0 - z1 } + luti4 { z0.b, z4.b, z8.b, z12.b }, { z0.b - z1.b } { z0 - z1 } + luti4 { z19.b, z23.b, z27.b, z31.b }, zt0, { } + luti4 { z19.b, z23.b, z27.b, z31.b }, z3, { z12 - z13 } + luti4 { z18.b, z22.b, z26.b, z30.b }, zt0, { z12 - z13 } + luti4 { z19.b, z23.b, z27.b, z31.b }, zt0, { z13 - z14 } + + // Disallowed types + luti4 { z20.s - z23.s }, zt0, { z20 - z21 } + luti4 { z19.s, z23.s, z27.s, z31.s }, zt0, { z20 - z21 } + + // Index with qualifiers + movt zt0.b, z31 + movt zt0.b[0, mul vl], z31 + + // Incorrect number of operands + movt zt0 + movt zt0[1, mul vl] + movt zt0, z23, z31 + movt zt0[1, mul vl], z23, z31 + + luti4 { z20.b - z23.b } + luti4 { z20.b - z23.b }, zt0 + luti4 { z20.b - z23.b }, zt0, { z12 - z13 }, { z20 - z21 } + + luti4 { z19.b, z23.b, z27.b, z31.b } + luti4 { z19.b, z23.b, z27.b, z31.b }, zt0 + luti4 { z19.b, z23.b, z27.b, z31.b }, zt0 { z12 - z13 }, { z20 - z21 } + + // Spelling mistakes + movt zy0, z16 + movt zt1, z16 + movt zy0[1, mul vl], z16 + movt zt0, y16 + movt zt0[1, mul vl], y16 + + luti4 { z20.b - y23.b }, zt0, { z12 - z13 } + luti4 { z20.x - z23.b }, zt0, { z12 - z13 } + luti4 { z20.b - z23.b }, zy0, { z12 - z13 } + luti4 { z20.b - y23.b }, zt0, { y12 - z13 } + + luti4 { z19.b, z23.b, z27.b, y31.b }, zt0, { z12 - z13 } + luti4 { z19.x, z23.b, z27.b, z31.b }, zt0, { z12 - z13 } + luti4 { z19.b, z23.b, z27.b, z31.b }, zy0, { z12 - z13 } + luti4 { z19.b, z23.b, z27.b, z31.b }, zt0, { y12 - z13 } + + // Missing qualifiers + luti4 { z20 - z23.b }, zt0, { z12 - z13 } + luti4 { z19.b, z23, z27.b, z31.b }, zt0, { z12 - z13 } + + // Qualifier on the wrong operand + movt zt, z25.b + luti4 { z20.b - z23.b }, zt0, { z12.b - z13.b } + luti4 { z19.b, z23.b, z27.b, z31.b }, zt0, { z12.b - z13.b } + + // Index on the wrong operand + movt zt0, z25[1] + movt zt0, z25[1, mul vl] + + // Out of range numbers + movt zt0[2, mul vl], z32 + movt zt0[4, mul vl], z25 + movt zt0[-1, mul vl], z25 + + luti4 { z32.b - z36.b }, zt0, { z12 - z13 } + luti4 { z20.b - z23.b }, zt0, { z32 - z33 } + + luti4 { z32.b, z36.b, z40.b, z44.b }, zt0, { z12 - z13 } + luti4 { z19.b, z23.b, z27.b, z31.b }, zt0, { z32 - z33 } + + // Incorrect stride + luti4 { z20.b - z24.b }, zt0, { z12 - z13 } + luti4 { z20.b - z22.b }, zt0, { z12 - z13 } + luti4 { z20.b - z23.b }, zt0, { z12 - z14 } + luti4 { z20.b - z23.b }, zt0, { z12 - z12 } + luti4 { z19.b, z24.b, z27.b, z31.b }, zt0, { z12 - z13 } + luti4 { z19.b, z22.b, z27.b, z31.b }, zt0, { z12 - z13 } + luti4 { z19.b, z23.b, z27.b, z31.b }, zt0, { z12 - z14 } diff --git a/gas/testsuite/gas/aarch64/sme2-lutv2.d b/gas/testsuite/gas/aarch64/sme2-lutv2.d new file mode 100644 index 00000000000..f671982c070 --- /dev/null +++ b/gas/testsuite/gas/aarch64/sme2-lutv2.d @@ -0,0 +1,24 @@ +#objdump: -dr +#as: -march=armv8-a+sme2+sme2p1+sme-lutv2 + +.*: file format .* + +Disassembly of section \.text: + +0+ <.*>: +[^:]+: c04f03e0 movt zt0\[0, mul vl\], z0 +[^:]+: c04f03ff movt zt0\[0, mul vl\], z31 +[^:]+: c04f33e0 movt zt0\[3, mul vl\], z0 +[^:]+: c04f33ff movt zt0\[3, mul vl\], z31 +[^:]+: c04f23f9 movt zt0\[2, mul vl\], z25 +[^:]+: c08b0000 luti4 {z0.b-z3.b}, zt0, {z0-z1} +[^:]+: c08b001c luti4 {z28.b-z31.b}, zt0, {z0-z1} +[^:]+: c08b03c0 luti4 {z0.b-z3.b}, zt0, {z30-z31} +[^:]+: c08b0194 luti4 {z20.b-z23.b}, zt0, {z12-z13} +[^:]+: c09b0000 luti4 {z0.b, z4.b, z8.b, z12.b}, zt0, {z0-z1} +[^:]+: c09b0013 luti4 {z19.b, z23.b, z27.b, z31.b}, zt0, {z0-z1} +[^:]+: c09b03c0 luti4 {z0.b, z4.b, z8.b, z12.b}, zt0, {z30-z31} +[^:]+: c09b0191 luti4 {z17.b, z21.b, z25.b, z29.b}, zt0, {z12-z13} +[^:]+: c08b0194 luti4 {z20.b-z23.b}, zt0, {z12-z13} +[^:]+: c08b2194 .inst 0xc08b2194 ; undefined +[^:]+: c09b2191 .inst 0xc09b2191 ; undefined diff --git a/gas/testsuite/gas/aarch64/sme2-lutv2.s b/gas/testsuite/gas/aarch64/sme2-lutv2.s new file mode 100644 index 00000000000..cba9ad93b79 --- /dev/null +++ b/gas/testsuite/gas/aarch64/sme2-lutv2.s @@ -0,0 +1,22 @@ + movt zt0, z0 + movt zt0[0, mul vl], z31 + movt zt0[3, mul vl], z0 + movt zt0[3, mul vl], z31 + movt zt0[2, mul vl], z25 + + luti4 { z0.b - z3.b }, zt0, { z0 - z1 } + luti4 { z28.b - z31.b }, zt0, { z0 - z1 } + luti4 { z0.b - z3.b }, zt0, { z30 - z31 } + luti4 { z20.b - z23.b }, zt0, { z12 - z13 } + + luti4 { z0.b, z4.b, z8.b, z12.b }, zt0, { z0 - z1 } + luti4 { z19.b, z23.b, z27.b, z31.b }, zt0, { z0 - z1 } + luti4 { z0.b, z4.b, z8.b, z12.b }, zt0, { z30 - z31 } + luti4 { z17.b, z21.b, z25.b, z29.b }, zt0, { z12 - z13 } + + // Explicitly listing registers in stride 1 variant + luti4 { z20.b, z21.b, z22.b, z23.b }, zt0, { z12 - z13 } + + // Invalid instructions because sz != 00 + .inst 0xc08b2194 + .inst 0xc09b2191 diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h index c83c0a4ebb4..19d25d6c261 100644 --- a/include/opcode/aarch64.h +++ b/include/opcode/aarch64.h @@ -240,6 +240,8 @@ enum aarch64_feature_bit { AARCH64_FEATURE_LUT, /* Branch Record Buffer Extension */ AARCH64_FEATURE_BRBE, + /* SME LUTv2 instructions. */ + AARCH64_FEATURE_SME_LUTv2, AARCH64_NUM_FEATURES }; @@ -759,10 +761,12 @@ enum aarch64_opnd AARCH64_OPND_SVE_ZtxN, /* SVE vector register list in Zt. */ AARCH64_OPND_SME_Zdnx2, /* SVE vector register list from [4:1]*2. */ AARCH64_OPND_SME_Zdnx4, /* SVE vector register list from [4:2]*4. */ + AARCH64_OPND_SME_Zdnx4_STRIDED, /* SVE vector register list from [4:2]*4. */ AARCH64_OPND_SME_Zm, /* SVE vector register list in 4-bit Zm. */ AARCH64_OPND_SME_Zmx2, /* SVE vector register list from [20:17]*2. */ AARCH64_OPND_SME_Zmx4, /* SVE vector register list from [20:18]*4. */ AARCH64_OPND_SME_Znx2, /* SVE vector register list from [9:6]*2. */ + AARCH64_OPND_SME_Znx2_BIT_INDEX, /* SVE vector register list encoding a bit index from [9:6]*2. */ AARCH64_OPND_SME_Znx4, /* SVE vector register list from [9:7]*4. */ AARCH64_OPND_SME_Ztx2_STRIDED, /* SVE vector register list in [4:0]&23. */ AARCH64_OPND_SME_Ztx4_STRIDED, /* SVE vector register list in [4:0]&19. */ @@ -811,6 +815,7 @@ enum aarch64_opnd AARCH64_OPND_SME_VLxN_13, /* VLx2 or VLx4, in bit 13. */ AARCH64_OPND_SME_ZT0, /* The fixed token zt0/ZT0 (not encoded). */ AARCH64_OPND_SME_ZT0_INDEX, /* ZT0[], bits [14:12]. */ + AARCH64_OPND_SME_ZT0_INDEX2_12, /* ZT0[], bits [13:12]. */ AARCH64_OPND_SME_ZT0_LIST, /* { zt0/ZT0 } (not encoded). */ AARCH64_OPND_TME_UIMM16, /* TME unsigned 16-bit immediate. */ AARCH64_OPND_SM3_IMM2, /* SM3 encodes lane in bits [13, 14]. */ @@ -1002,6 +1007,7 @@ enum aarch64_insn_class sme_shift, sme_size_12_bhs, sme_size_12_hs, + sme_size_12_b, sme_size_22, sme_size_22_hsd, sme_sz_23, diff --git a/opcodes/aarch64-asm.c b/opcodes/aarch64-asm.c index 5c6a31167c6..57fb8614dd0 100644 --- a/opcodes/aarch64-asm.c +++ b/opcodes/aarch64-asm.c @@ -2145,6 +2145,7 @@ aarch64_encode_variant_using_iclass (struct aarch64_inst *inst) break; case sme_size_12_bhs: + case sme_size_12_b: insert_field (FLD_SME_size_12, &inst->value, aarch64_get_variant (inst), 0); break; diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c index 213df616608..045af49228a 100644 --- a/opcodes/aarch64-dis.c +++ b/opcodes/aarch64-dis.c @@ -3415,6 +3415,12 @@ aarch64_decode_variant_using_iclass (aarch64_inst *inst) variant -= 1; break; + case sme_size_12_b: + variant = extract_field (FLD_SME_size_12, inst->value, 0); + if (variant != 0) + return false; + break; + case sme_size_22: variant = extract_field (FLD_SME_size_22, inst->value, 0); break; diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c index ea278bfdfe5..b70467391bc 100644 --- a/opcodes/aarch64-opc.c +++ b/opcodes/aarch64-opc.c @@ -258,7 +258,9 @@ const aarch64_field fields[] = { 13, 1 }, /* SME_VL_13: VLx2 or VLx4, bit [13]. */ { 0, 2 }, /* SME_ZAda_2b: tile ZA0-ZA3. */ { 0, 3 }, /* SME_ZAda_3b: tile ZA0-ZA7. */ + { 4, 1 }, /* SME_ZdnT: upper bit of Zt, bit [4]. */ { 1, 4 }, /* SME_Zdn2: Z0-Z31, multiple of 2, bits [4:1]. */ + { 0, 2 }, /* SME_Zdn2_0: lower 2 bits of Zt, bits [1:0]. */ { 2, 3 }, /* SME_Zdn4: Z0-Z31, multiple of 4, bits [4:2]. */ { 16, 4 }, /* SME_Zm: Z0-Z15, bits [19:16]. */ { 17, 4 }, /* SME_Zm2: Z0-Z31, multiple of 2, bits [20:17]. */ @@ -1919,6 +1921,7 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx, case AARCH64_OPND_SME_Zmx2: case AARCH64_OPND_SME_Zmx4: case AARCH64_OPND_SME_Znx2: + case AARCH64_OPND_SME_Znx2_BIT_INDEX: case AARCH64_OPND_SME_Znx4: case AARCH64_OPND_SME_Zt2: case AARCH64_OPND_SME_Zt3: @@ -1934,6 +1937,7 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx, } break; + case AARCH64_OPND_SME_Zdnx4_STRIDED: case AARCH64_OPND_SME_Ztx2_STRIDED: case AARCH64_OPND_SME_Ztx4_STRIDED: /* 2-register lists have a stride of 8 and 4-register lists @@ -3153,6 +3157,14 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx, } break; + case AARCH64_OPND_SME_ZT0_INDEX2_12: + if (!value_in_range_p (opnd->imm.value, 0, 3)) + { + set_elem_idx_out_of_range_error (mismatch_detail, idx, 0, 3); + return 0; + } + break; + default: break; } @@ -3745,9 +3757,14 @@ print_register_list (char *buf, size_t size, const aarch64_opnd_info *opnd, && ((opnd->type != AARCH64_OPND_SME_Zt2) && (opnd->type != AARCH64_OPND_SME_Zt3) && (opnd->type != AARCH64_OPND_SME_Zt4))) - snprintf (buf, size, "{%s-%s}%s", - style_reg (styler, "%s%d.%s", prefix, first_reg, qlf_name), - style_reg (styler, "%s%d.%s", prefix, last_reg, qlf_name), tb); + if (opnd->qualifier == AARCH64_OPND_QLF_NIL) + snprintf (buf, size, "{%s-%s}%s", + style_reg (styler, "%s%d", prefix, first_reg), + style_reg (styler, "%s%d", prefix, last_reg), tb); + else + snprintf (buf, size, "{%s-%s}%s", + style_reg (styler, "%s%d.%s", prefix, first_reg, qlf_name), + style_reg (styler, "%s%d.%s", prefix, last_reg, qlf_name), tb); else { const int reg0 = first_reg; @@ -4216,9 +4233,11 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc, case AARCH64_OPND_SVE_ZtxN: case AARCH64_OPND_SME_Zdnx2: case AARCH64_OPND_SME_Zdnx4: + case AARCH64_OPND_SME_Zdnx4_STRIDED: case AARCH64_OPND_SME_Zmx2: case AARCH64_OPND_SME_Zmx4: case AARCH64_OPND_SME_Znx2: + case AARCH64_OPND_SME_Znx2_BIT_INDEX: case AARCH64_OPND_SME_Znx4: case AARCH64_OPND_SME_Ztx2_STRIDED: case AARCH64_OPND_SME_Ztx4_STRIDED: @@ -4906,6 +4925,11 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc, snprintf (buf, size, "%s[%s]", style_reg (styler, "zt0"), style_imm (styler, "%d", (int) opnd->imm.value)); break; + case AARCH64_OPND_SME_ZT0_INDEX2_12: + snprintf (buf, size, "%s[%s, %s]", style_reg (styler, "zt0"), + style_imm (styler, "%d", (int) opnd->imm.value), + style_sub_mnem (styler, "mul vl")); + break; case AARCH64_OPND_SME_ZT0_LIST: snprintf (buf, size, "{%s}", style_reg (styler, "zt0")); diff --git a/opcodes/aarch64-opc.h b/opcodes/aarch64-opc.h index 9b734d63a3b..8804e7c0038 100644 --- a/opcodes/aarch64-opc.h +++ b/opcodes/aarch64-opc.h @@ -62,7 +62,9 @@ enum aarch64_field_kind FLD_SME_VL_13, FLD_SME_ZAda_2b, FLD_SME_ZAda_3b, + FLD_SME_ZdnT, FLD_SME_Zdn2, + FLD_SME_Zdn2_0, FLD_SME_Zdn4, FLD_SME_Zm, FLD_SME_Zm2, diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h index bffb422583a..58765928539 100644 --- a/opcodes/aarch64-tbl.h +++ b/opcodes/aarch64-tbl.h @@ -1814,6 +1814,13 @@ { \ QLF2(S_S,NIL), \ } +/* e.g. movt ZT0{[, MUL VL]}, */ +/* The second operand doesn't have a qualifier and + is checked separetely during encoding. */ +#define OP_SVE_SU_Q \ +{ \ + QLF2(S_Q,NIL), \ +} #define OP_SVE_SUS \ { \ QLF3(S_S,NIL,S_S), \ @@ -2050,6 +2057,13 @@ QLF3(S_S,NIL,W), \ QLF3(S_D,NIL,X), \ } +/* e.g. luti4 { .B-.B }, ZT0, { - } */ +/* The second and third operands don't have qualifiers and + are checked separetely during encoding. */ +#define OP_SVE_VUU_B \ +{ \ + QLF3(S_B,NIL,NIL), \ +} #define OP_SVE_VUU_BHS \ { \ QLF3(S_B,NIL,NIL), \ @@ -2752,6 +2766,8 @@ static const aarch64_feature_set aarch64_feature_lut_sve2 = AARCH64_FEATURES (2, LUT, SVE2); static const aarch64_feature_set aarch64_feature_brbe = AARCH64_FEATURE (BRBE); +static const aarch64_feature_set aarch64_feature_sme_lutv2 = + AARCH64_FEATURES (3, SME_LUTv2, SME2, SME2p1); #define CORE &aarch64_feature_v8 #define FP &aarch64_feature_fp @@ -2829,6 +2845,7 @@ static const aarch64_feature_set aarch64_feature_brbe = #define LUT &aarch64_feature_lut #define LUT_SVE2 &aarch64_feature_lut_sve2 #define BRBE &aarch64_feature_brbe +#define LUTv2_SME2 &aarch64_feature_sme_lutv2 #define CORE_INSN(NAME,OPCODE,MASK,CLASS,OP,OPS,QUALS,FLAGS) \ { NAME, OPCODE, MASK, CLASS, OP, CORE, OPS, QUALS, FLAGS, 0, 0, NULL } @@ -3029,6 +3046,9 @@ static const aarch64_feature_set aarch64_feature_brbe = FLAGS, CONSTRAINTS, 0, NULL } #define BRBE_INSN(NAME,OPCODE,MASK,OPS,QUALS,FLAGS) \ { NAME, OPCODE, MASK, ic_system, 0, BRBE, OPS, QUALS, FLAGS, 0, 0, NULL } +#define LUTv2_SME2_INSN(NAME,OPCODE,MASK,CLASS,OPS,QUALS,FLAGS) \ + { NAME, OPCODE, MASK, CLASS, 0, LUTv2_SME2, OPS, QUALS, \ + FLAGS, 0, 0, NULL } #define MOPS_CPY_OP1_OP2_PME_INSN(NAME, OPCODE, MASK, FLAGS, CONSTRAINTS) \ MOPS_INSN (NAME, OPCODE, MASK, 0, \ @@ -6615,6 +6635,11 @@ const struct aarch64_opcode aarch64_opcode_table[] = LUT_SVE2_INSN ("luti4", 0x4520b400, 0xff20fc00, OP3 (SVE_Zd, SVE_ZnxN, SVE_Zm2_22_INDEX), OP_SVE_HHU, F_OD(2), 0), LUT_SVE2_INSN ("luti4", 0x4520bc00, 0xff20fc00, OP3 (SVE_Zd, SVE_ZnxN, SVE_Zm2_22_INDEX), OP_SVE_HHU, F_OD(1), 0), + /* SME2 lutv2. */ + LUTv2_SME2_INSN ("luti4", 0xc08b0000, 0xffffcc23, sme_size_12_b, OP3 (SME_Zdnx4, SME_ZT0, SME_Znx2_BIT_INDEX), OP_SVE_VUU_B, F_STRICT | 0), + LUTv2_SME2_INSN ("luti4", 0xc09b0000, 0xffffcc2c, sme_size_12_b, OP3 (SME_Zdnx4_STRIDED, SME_ZT0, SME_Znx2_BIT_INDEX), OP_SVE_VUU_B, F_STRICT | 0), + LUTv2_SME2_INSN ("movt", 0xc04f03e0, 0xffffcfe0, sme_misc, OP2 (SME_ZT0_INDEX2_12, SVE_Zt), {}, 0), + {0, 0, 0, 0, 0, 0, {}, {}, 0, 0, 0, NULL}, }; @@ -7139,6 +7164,9 @@ const struct aarch64_opcode aarch64_opcode_table[] = F(FLD_SME_Zdn2), "a list of SVE vector registers") \ Y(SVE_REGLIST, sve_aligned_reglist, "SME_Zdnx4", 4 << OPD_F_OD_LSB, \ F(FLD_SME_Zdn4), "a list of SVE vector registers") \ + Y(SVE_REGLIST, sve_strided_reglist, "SME_Zdnx4_STRIDED", \ + 4 << OPD_F_OD_LSB, F(FLD_SME_ZdnT, FLD_SME_Zdn2_0), \ + "a list of SVE vector registers") \ Y(SVE_REG, regno, "SME_Zm", 0, F(FLD_SME_Zm), \ "an SVE vector register") \ Y(SVE_REGLIST, sve_aligned_reglist, "SME_Zmx2", 2 << OPD_F_OD_LSB, \ @@ -7147,6 +7175,9 @@ const struct aarch64_opcode aarch64_opcode_table[] = F(FLD_SME_Zm4), "a list of SVE vector registers") \ Y(SVE_REGLIST, sve_aligned_reglist, "SME_Znx2", 2 << OPD_F_OD_LSB, \ F(FLD_SME_Zn2), "a list of SVE vector registers") \ + Y(SVE_REGLIST, sve_aligned_reglist, "SME_Znx2_BIT_INDEX", \ + 2 << OPD_F_OD_LSB, F(FLD_SME_Zn2), \ + "a list of SVE vector registers") \ Y(SVE_REGLIST, sve_aligned_reglist, "SME_Znx4", 4 << OPD_F_OD_LSB, \ F(FLD_SME_Zn4), "a list of SVE vector registers") \ Y(SVE_REGLIST, sve_strided_reglist, "SME_Ztx2_STRIDED", \ @@ -7257,6 +7288,8 @@ const struct aarch64_opcode aarch64_opcode_table[] = Y(SYSTEM, none, "SME_ZT0", 0, F (), "ZT0") \ Y(IMMEDIATE, imm, "SME_ZT0_INDEX", OPD_F_SHIFT_BY_3, \ F (FLD_imm3_12), "a ZT0 index") \ + Y(IMMEDIATE, imm, "SME_ZT0_INDEX2_12", 0, \ + F (FLD_imm3_12), "a ZT0 index") \ Y(SYSTEM, none, "SME_ZT0_LIST", 0, F (), "{ ZT0 }") \ Y(IMMEDIATE, imm, "TME_UIMM16", 0, F(FLD_imm16_5), \ "a 16-bit unsigned immediate for TME tcancel") \