[v6,1/4] gas, aarch64: Add AdvSIMD lut extension

Message ID 20240523135020.2492458-1-saujha01@e130340.arm.com
State Superseded
Headers
Series [v6,1/4] gas, aarch64: Add AdvSIMD lut extension |

Checks

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

Commit Message

Saurabh Jha May 23, 2024, 1:50 p.m. UTC
  Introduces instructions for the Advanced SIMD lut extension for AArch64. They are documented in the following links:
* luti2: https://developer.arm.com/documentation/ddi0602/2024-03/SIMD-FP-Instructions/LUTI2--Lookup-table-read-with-2-bit-indices-?lang=en
* luti4: https://developer.arm.com/documentation/ddi0602/2024-03/SIMD-FP-Instructions/LUTI4--Lookup-table-read-with-4-bit-indices-?lang=en

These instructions needed definition of some new operands. We will first
discuss operands for the third operand of the instructions and then
discuss a vector register list operand needed for the second operand.

The third operands are vectors with bit indices and without type
qualifiers. They are called Em_INDEX1_14, Em_INDEX2_13, and Em_INDEX3_12
and they have 1 bit, 2 bit, and 3 bit indices respectively. For these
new operands, we defined new parsing case branch and a new instruction
class. The lsb and width of these operands are the same as many existing
but the convention is to give different names to fields that serve
different purpose so we introduced new fields in aarch64-opc.c and
aarch64-opc.h for these new operands.

For the second operand of these instructions, we introduced a new
operand called LVn_LUT. This represents a vector register list with
stride 1. We defined new inserter and extractor for this new operand and
it is encoded in FLD_Rn. We are enforcing the number of registers in the
reglist using opcode flag rather than operand flag as this is what other
SIMD vector register list operands are doing. The disassembly also uses
opcode flag to print the correct number of registers.
---
Hi,

Regression tested for aarch64-none-elf and found no regressions.

Ok for binutils-master? I don't have commit access so can someone please commit on my behalf?

Regards,
Saurabh
---
 gas/config/tc-aarch64.c                       |  67 ++++++
 gas/testsuite/gas/aarch64/advsimd-lut-bad.d   |   3 +
 gas/testsuite/gas/aarch64/advsimd-lut-bad.l   |  25 +++
 .../gas/aarch64/advsimd-lut-illegal.d         |   3 +
 .../gas/aarch64/advsimd-lut-illegal.l         | 208 ++++++++++++++++++
 .../gas/aarch64/advsimd-lut-illegal.s         | 128 +++++++++++
 gas/testsuite/gas/aarch64/advsimd-lut.d       |  32 +++
 gas/testsuite/gas/aarch64/advsimd-lut.s       |  29 +++
 include/opcode/aarch64.h                      |   9 +-
 opcodes/aarch64-asm.c                         |  32 +++
 opcodes/aarch64-asm.h                         |   1 +
 opcodes/aarch64-dis.c                         |  15 ++
 opcodes/aarch64-dis.h                         |   1 +
 opcodes/aarch64-opc.c                         |  23 ++
 opcodes/aarch64-opc.h                         |   2 +
 opcodes/aarch64-tbl.h                         |  38 +++-
 16 files changed, 614 insertions(+), 2 deletions(-)
 create mode 100644 gas/testsuite/gas/aarch64/advsimd-lut-bad.d
 create mode 100644 gas/testsuite/gas/aarch64/advsimd-lut-bad.l
 create mode 100644 gas/testsuite/gas/aarch64/advsimd-lut-illegal.d
 create mode 100644 gas/testsuite/gas/aarch64/advsimd-lut-illegal.l
 create mode 100644 gas/testsuite/gas/aarch64/advsimd-lut-illegal.s
 create mode 100644 gas/testsuite/gas/aarch64/advsimd-lut.d
 create mode 100644 gas/testsuite/gas/aarch64/advsimd-lut.s
  

Comments

Richard Earnshaw (lists) May 23, 2024, 3:15 p.m. UTC | #1
On 23/05/2024 14:50, Saurabh Jha wrote:
> 
> Introduces instructions for the Advanced SIMD lut extension for AArch64. They are documented in the following links:
> * luti2: https://developer.arm.com/documentation/ddi0602/2024-03/SIMD-FP-Instructions/LUTI2--Lookup-table-read-with-2-bit-indices-?lang=en
> * luti4: https://developer.arm.com/documentation/ddi0602/2024-03/SIMD-FP-Instructions/LUTI4--Lookup-table-read-with-4-bit-indices-?lang=en
> 
> These instructions needed definition of some new operands. We will first
> discuss operands for the third operand of the instructions and then
> discuss a vector register list operand needed for the second operand.
> 
> The third operands are vectors with bit indices and without type
> qualifiers. They are called Em_INDEX1_14, Em_INDEX2_13, and Em_INDEX3_12
> and they have 1 bit, 2 bit, and 3 bit indices respectively. For these
> new operands, we defined new parsing case branch and a new instruction
> class. The lsb and width of these operands are the same as many existing
> but the convention is to give different names to fields that serve
> different purpose so we introduced new fields in aarch64-opc.c and
> aarch64-opc.h for these new operands.
> 
> For the second operand of these instructions, we introduced a new
> operand called LVn_LUT. This represents a vector register list with
> stride 1. We defined new inserter and extractor for this new operand and
> it is encoded in FLD_Rn. We are enforcing the number of registers in the
> reglist using opcode flag rather than operand flag as this is what other
> SIMD vector register list operands are doing. The disassembly also uses
> opcode flag to print the correct number of registers.
> ---
> Hi,
> 
> Regression tested for aarch64-none-elf and found no regressions.
> 
> Ok for binutils-master? I don't have commit access so can someone please commit on my behalf?

I was about to apply this when I realized that you haven't added anything to the manual or the NEWS file as we could customarily do for a new feature.  Could you update the patch for that please?

R.

> 
> Regards,
> Saurabh
> ---
>  gas/config/tc-aarch64.c                       |  67 ++++++
>  gas/testsuite/gas/aarch64/advsimd-lut-bad.d   |   3 +
>  gas/testsuite/gas/aarch64/advsimd-lut-bad.l   |  25 +++
>  .../gas/aarch64/advsimd-lut-illegal.d         |   3 +
>  .../gas/aarch64/advsimd-lut-illegal.l         | 208 ++++++++++++++++++
>  .../gas/aarch64/advsimd-lut-illegal.s         | 128 +++++++++++
>  gas/testsuite/gas/aarch64/advsimd-lut.d       |  32 +++
>  gas/testsuite/gas/aarch64/advsimd-lut.s       |  29 +++
>  include/opcode/aarch64.h                      |   9 +-
>  opcodes/aarch64-asm.c                         |  32 +++
>  opcodes/aarch64-asm.h                         |   1 +
>  opcodes/aarch64-dis.c                         |  15 ++
>  opcodes/aarch64-dis.h                         |   1 +
>  opcodes/aarch64-opc.c                         |  23 ++
>  opcodes/aarch64-opc.h                         |   2 +
>  opcodes/aarch64-tbl.h                         |  38 +++-
>  16 files changed, 614 insertions(+), 2 deletions(-)
>  create mode 100644 gas/testsuite/gas/aarch64/advsimd-lut-bad.d
>  create mode 100644 gas/testsuite/gas/aarch64/advsimd-lut-bad.l
>  create mode 100644 gas/testsuite/gas/aarch64/advsimd-lut-illegal.d
>  create mode 100644 gas/testsuite/gas/aarch64/advsimd-lut-illegal.l
>  create mode 100644 gas/testsuite/gas/aarch64/advsimd-lut-illegal.s
>  create mode 100644 gas/testsuite/gas/aarch64/advsimd-lut.d
>  create mode 100644 gas/testsuite/gas/aarch64/advsimd-lut.s
>
  
Andrew Carlotti May 23, 2024, 4:08 p.m. UTC | #2
On Thu, May 23, 2024 at 02:50:16PM +0100, Saurabh Jha wrote:
> 
> Introduces instructions for the Advanced SIMD lut extension for AArch64. They are documented in the following links:
> * luti2: https://developer.arm.com/documentation/ddi0602/2024-03/SIMD-FP-Instructions/LUTI2--Lookup-table-read-with-2-bit-indices-?lang=en
> * luti4: https://developer.arm.com/documentation/ddi0602/2024-03/SIMD-FP-Instructions/LUTI4--Lookup-table-read-with-4-bit-indices-?lang=en
> 
> These instructions needed definition of some new operands. We will first
> discuss operands for the third operand of the instructions and then
> discuss a vector register list operand needed for the second operand.
> 
> The third operands are vectors with bit indices and without type
> qualifiers. They are called Em_INDEX1_14, Em_INDEX2_13, and Em_INDEX3_12
> and they have 1 bit, 2 bit, and 3 bit indices respectively. For these
> new operands, we defined new parsing case branch and a new instruction
> class. The lsb and width of these operands are the same as many existing
> but the convention is to give different names to fields that serve
> different purpose so we introduced new fields in aarch64-opc.c and
> aarch64-opc.h for these new operands.
> 
> For the second operand of these instructions, we introduced a new
> operand called LVn_LUT. This represents a vector register list with
> stride 1. We defined new inserter and extractor for this new operand and
> it is encoded in FLD_Rn. We are enforcing the number of registers in the
> reglist using opcode flag rather than operand flag as this is what other
> SIMD vector register list operands are doing. The disassembly also uses
> opcode flag to print the correct number of registers.
> ---
> Hi,
> 
> Regression tested for aarch64-none-elf and found no regressions.
> 
> Ok for binutils-master? I don't have commit access so can someone please commit on my behalf?
> 
> Regards,
> Saurabh
...
> diff --git a/opcodes/aarch64-asm.c b/opcodes/aarch64-asm.c
> index 5a55ca2f86d..338ed54165d 100644
> --- a/opcodes/aarch64-asm.c
> +++ b/opcodes/aarch64-asm.c
> @@ -168,6 +168,27 @@ aarch64_ins_reglane (const aarch64_operand *self, const aarch64_opnd_info *info,
>        assert (reglane_index < 4);
>        insert_field (FLD_SM3_imm2, code, reglane_index, 0);
>      }
> +  else if (inst->opcode->iclass == lut)
> +    {
> +      unsigned reglane_index = info->reglane.index;
> +      switch (info->type)
> +	{
> +	case AARCH64_OPND_Em_INDEX1_14:
> +	  assert (reglane_index < 2);
> +	  insert_field (FLD_imm1_14, code, reglane_index, 0);
> +	  break;
> +	case AARCH64_OPND_Em_INDEX2_13:
> +	  assert (reglane_index < 4);
> +	  insert_field (FLD_imm2_13, code, reglane_index, 0);
> +	  break;
> +	case AARCH64_OPND_Em_INDEX3_12:
> +	  assert (reglane_index < 8);
> +	  insert_field (FLD_imm3_12, code, reglane_index, 0);
> +	  break;
> +	default:
> +	  return false;
> +	}
> +    }
>    else
>      {
>        /* index for e.g. SQDMLAL <Va><d>, <Vb><n>, <Vm>.<Ts>[<index>]

This hunk should be dropped now that these operands use the simple_index inserter/extractor.
  
Saurabh Jha May 28, 2024, 2:59 p.m. UTC | #3
On 5/23/2024 4:15 PM, Richard Earnshaw (lists) wrote:
> On 23/05/2024 14:50, Saurabh Jha wrote:
>>
>> Introduces instructions for the Advanced SIMD lut extension for AArch64. They are documented in the following links:
>> * luti2: https://developer.arm.com/documentation/ddi0602/2024-03/SIMD-FP-Instructions/LUTI2--Lookup-table-read-with-2-bit-indices-?lang=en
>> * luti4: https://developer.arm.com/documentation/ddi0602/2024-03/SIMD-FP-Instructions/LUTI4--Lookup-table-read-with-4-bit-indices-?lang=en
>>
>> These instructions needed definition of some new operands. We will first
>> discuss operands for the third operand of the instructions and then
>> discuss a vector register list operand needed for the second operand.
>>
>> The third operands are vectors with bit indices and without type
>> qualifiers. They are called Em_INDEX1_14, Em_INDEX2_13, and Em_INDEX3_12
>> and they have 1 bit, 2 bit, and 3 bit indices respectively. For these
>> new operands, we defined new parsing case branch and a new instruction
>> class. The lsb and width of these operands are the same as many existing
>> but the convention is to give different names to fields that serve
>> different purpose so we introduced new fields in aarch64-opc.c and
>> aarch64-opc.h for these new operands.
>>
>> For the second operand of these instructions, we introduced a new
>> operand called LVn_LUT. This represents a vector register list with
>> stride 1. We defined new inserter and extractor for this new operand and
>> it is encoded in FLD_Rn. We are enforcing the number of registers in the
>> reglist using opcode flag rather than operand flag as this is what other
>> SIMD vector register list operands are doing. The disassembly also uses
>> opcode flag to print the correct number of registers.
>> ---
>> Hi,
>>
>> Regression tested for aarch64-none-elf and found no regressions.
>>
>> Ok for binutils-master? I don't have commit access so can someone please commit on my behalf?
> 
> I was about to apply this when I realized that you haven't added anything to the manual or the NEWS file as we could customarily do for a new feature.  Could you update the patch for that please?
> 
> R.
> 

Yes, thanks for pointing it out. Fixed here: 
https://sourceware.org/pipermail/binutils/2024-May/134334.html
>>
>> Regards,
>> Saurabh
>> ---
>>   gas/config/tc-aarch64.c                       |  67 ++++++
>>   gas/testsuite/gas/aarch64/advsimd-lut-bad.d   |   3 +
>>   gas/testsuite/gas/aarch64/advsimd-lut-bad.l   |  25 +++
>>   .../gas/aarch64/advsimd-lut-illegal.d         |   3 +
>>   .../gas/aarch64/advsimd-lut-illegal.l         | 208 ++++++++++++++++++
>>   .../gas/aarch64/advsimd-lut-illegal.s         | 128 +++++++++++
>>   gas/testsuite/gas/aarch64/advsimd-lut.d       |  32 +++
>>   gas/testsuite/gas/aarch64/advsimd-lut.s       |  29 +++
>>   include/opcode/aarch64.h                      |   9 +-
>>   opcodes/aarch64-asm.c                         |  32 +++
>>   opcodes/aarch64-asm.h                         |   1 +
>>   opcodes/aarch64-dis.c                         |  15 ++
>>   opcodes/aarch64-dis.h                         |   1 +
>>   opcodes/aarch64-opc.c                         |  23 ++
>>   opcodes/aarch64-opc.h                         |   2 +
>>   opcodes/aarch64-tbl.h                         |  38 +++-
>>   16 files changed, 614 insertions(+), 2 deletions(-)
>>   create mode 100644 gas/testsuite/gas/aarch64/advsimd-lut-bad.d
>>   create mode 100644 gas/testsuite/gas/aarch64/advsimd-lut-bad.l
>>   create mode 100644 gas/testsuite/gas/aarch64/advsimd-lut-illegal.d
>>   create mode 100644 gas/testsuite/gas/aarch64/advsimd-lut-illegal.l
>>   create mode 100644 gas/testsuite/gas/aarch64/advsimd-lut-illegal.s
>>   create mode 100644 gas/testsuite/gas/aarch64/advsimd-lut.d
>>   create mode 100644 gas/testsuite/gas/aarch64/advsimd-lut.s
>>
>
  

Patch

diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index 3f838cfd9a0..41547866d2c 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -1513,6 +1513,54 @@  parse_vector_reg_list (char **ccp, aarch64_reg_type type,
   return error ? PARSE_FAIL : (ret_val << 2) | (nb_regs - 1);
 }
 
+/* Parse a SIMD vector register with a bit index. The SIMD vectors with
+   bit indices don't have type qualifiers.
+
+   Return null if the string pointed to by *CCP is not a valid AdvSIMD
+   vector register with a bit index.
+
+   Otherwise return the register and the bit index information
+   in *typeinfo.
+
+   The validity of the bit index itself is checked separately in encoding.
+ */
+
+static const reg_entry *
+parse_simd_vector_with_bit_index (char **ccp, struct vector_type_el *typeinfo)
+{
+  char *str = *ccp;
+  const reg_entry *reg = parse_reg (&str);
+  struct vector_type_el atype;
+
+  // Setting it here as this is the convention followed in the
+  // rest of the code with indices.
+  atype.defined = NTA_HASINDEX;
+  // This will be set to correct value in parse_index_expressions.
+  atype.index = 0;
+  // The rest of the fields are not applicable for this operand.
+  atype.type = NT_invtype;
+  atype.width = -1;
+  atype.element_size = 0;
+
+  if (reg == NULL)
+    return NULL;
+
+  if (reg->type != REG_TYPE_V)
+    return NULL;
+
+  // Parse the bit index.
+  if (!skip_past_char (&str, '['))
+    return NULL;
+  if (!parse_index_expression (&str, &atype.index))
+    return NULL;
+  if (!skip_past_char (&str, ']'))
+    return NULL;
+
+  *typeinfo = atype;
+  *ccp = str;
+  return reg;
+}
+
 /* Directives: register aliases.  */
 
 static reg_entry *
@@ -6790,6 +6838,23 @@  parse_operands (char *str, const aarch64_opcode *opcode)
 	  info->reglane.index = vectype.index;
 	  break;
 
+	case AARCH64_OPND_Em_INDEX1_14:
+	case AARCH64_OPND_Em_INDEX2_13:
+	case AARCH64_OPND_Em_INDEX3_12:
+	  // These are SIMD vector operands with bit indices. For example,
+	  // 'V27[3]'. These operands don't have type qualifiers before
+	  // indices.
+	  reg = parse_simd_vector_with_bit_index(&str, &vectype);
+
+	  if (!reg)
+	    goto failure;
+	  gas_assert (vectype.defined & NTA_HASINDEX);
+
+	  info->qualifier = AARCH64_OPND_QLF_NIL;
+	  info->reglane.regno = reg->number;
+	  info->reglane.index = vectype.index;
+	  break;
+
 	case AARCH64_OPND_SVE_ZnxN:
 	case AARCH64_OPND_SVE_ZtxN:
 	case AARCH64_OPND_SME_Zdnx2:
@@ -6812,6 +6877,7 @@  parse_operands (char *str, const aarch64_opcode *opcode)
 	  goto vector_reg_list;
 
 	case AARCH64_OPND_LVn:
+	case AARCH64_OPND_LVn_LUT:
 	case AARCH64_OPND_LVt:
 	case AARCH64_OPND_LVt_AL:
 	case AARCH64_OPND_LEt:
@@ -10481,6 +10547,7 @@  static const struct aarch64_option_cpu_value_table aarch64_features[] = {
   {"cpa",		AARCH64_FEATURE (CPA), AARCH64_NO_FEATURES},
   {"faminmax",		AARCH64_FEATURE (FAMINMAX), AARCH64_FEATURE (SIMD)},
   {"fp8",		AARCH64_FEATURE (FP8), AARCH64_FEATURE (SIMD)},
+  {"lut",		AARCH64_FEATURE (LUT), AARCH64_FEATURE (SIMD)},
   {NULL,		AARCH64_NO_FEATURES, AARCH64_NO_FEATURES},
 };
 
diff --git a/gas/testsuite/gas/aarch64/advsimd-lut-bad.d b/gas/testsuite/gas/aarch64/advsimd-lut-bad.d
new file mode 100644
index 00000000000..a3b57730e9b
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/advsimd-lut-bad.d
@@ -0,0 +1,3 @@ 
+#as:
+#source: advsimd-lut.s
+#error_output: advsimd-lut-bad.l
\ No newline at end of file
diff --git a/gas/testsuite/gas/aarch64/advsimd-lut-bad.l b/gas/testsuite/gas/aarch64/advsimd-lut-bad.l
new file mode 100644
index 00000000000..3afe4a39c54
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/advsimd-lut-bad.l
@@ -0,0 +1,25 @@ 
+[^ :]+: Assembler messages:
+.*: Error: selected processor does not support `luti2 v0.16b,{v0.16b},v0\[0\]'
+.*: Error: selected processor does not support `luti2 v31.16b,{v0.16b},v0\[0\]'
+.*: Error: selected processor does not support `luti2 v0.16b,{v31.16b},v0\[0\]'
+.*: Error: selected processor does not support `luti2 v0.16b,{v0.16b},v31\[0\]'
+.*: Error: selected processor does not support `luti2 v0.16b,{v0.16b},v31\[3\]'
+.*: Error: selected processor does not support `luti2 v17.16b,{v21.16b},v27\[2\]'
+.*: Error: selected processor does not support `luti2 v0.8h,{v0.8h},v0\[0\]'
+.*: Error: selected processor does not support `luti2 v31.8h,{v0.8h},v0\[0\]'
+.*: Error: selected processor does not support `luti2 v0.8h,{v31.8h},v0\[0\]'
+.*: Error: selected processor does not support `luti2 v0.8h,{v0.8h},v31\[0\]'
+.*: Error: selected processor does not support `luti2 v0.8h,{v0.8h},v0\[7\]'
+.*: Error: selected processor does not support `luti2 v17.8h,{v21.8h},v27\[4\]'
+.*: Error: selected processor does not support `luti4 v0.16b,{v0.16b},v0\[0\]'
+.*: Error: selected processor does not support `luti4 v31.16b,{v0.16b},v0\[0\]'
+.*: Error: selected processor does not support `luti4 v0.16b,{v31.16b},v0\[0\]'
+.*: Error: selected processor does not support `luti4 v0.16b,{v0.16b},v31\[0\]'
+.*: Error: selected processor does not support `luti4 v0.16b,{v0.16b},v0\[1\]'
+.*: Error: selected processor does not support `luti4 v17.16b,{v21.16b},v27\[1\]'
+.*: Error: selected processor does not support `luti4 v0.8h,{v0.8h,v1.8h},v0\[0\]'
+.*: Error: selected processor does not support `luti4 v31.8h,{v0.8h,v1.8h},v0\[0\]'
+.*: Error: selected processor does not support `luti4 v0.8h,{v31.8h,v0.8h},v0\[0\]'
+.*: Error: selected processor does not support `luti4 v0.8h,{v0.8h,v1.8h},v31\[0\]'
+.*: Error: selected processor does not support `luti4 v0.8h,{v0.8h,v1.8h},v0\[3\]'
+.*: Error: selected processor does not support `luti4 v17.8h,{v21.8h,v22.8h},v27\[2\]'
diff --git a/gas/testsuite/gas/aarch64/advsimd-lut-illegal.d b/gas/testsuite/gas/aarch64/advsimd-lut-illegal.d
new file mode 100644
index 00000000000..32ddfebabe1
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/advsimd-lut-illegal.d
@@ -0,0 +1,3 @@ 
+#as: -march=armv8-a+lut
+#source: advsimd-lut-illegal.s
+#error_output: advsimd-lut-illegal.l
\ No newline at end of file
diff --git a/gas/testsuite/gas/aarch64/advsimd-lut-illegal.l b/gas/testsuite/gas/aarch64/advsimd-lut-illegal.l
new file mode 100644
index 00000000000..86f6a7d2fdb
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/advsimd-lut-illegal.l
@@ -0,0 +1,208 @@ 
+[^ :]+: Assembler messages:
+[^ :]+:[0-9]+: Error: operand mismatch -- `luti2 v2.16b,\{v4.8h\},v8\[1\]'
+[^ :]+:[0-9]+: Info:    did you mean this\?
+[^ :]+:[0-9]+: Info:    	luti2 v2.16b, \{v4.16b\}, v8\[1\]
+[^ :]+:[0-9]+: Error: operand mismatch -- `luti2 v2.8h,\{v4.16b\},v8\[1\]'
+[^ :]+:[0-9]+: Info:    did you mean this\?
+[^ :]+:[0-9]+: Info:    	luti2 v2.16b, \{v4.16b\}, v8\[1\]
+[^ :]+:[0-9]+: Error: operand mismatch -- `luti4 v2.16b,\{v4.8h\},v8\[5\]'
+[^ :]+:[0-9]+: Info:    did you mean this\?
+[^ :]+:[0-9]+: Info:    	luti4 v2.16b, \{v4.16b\}, v8\[5\]
+[^ :]+:[0-9]+: Error: operand mismatch -- `luti4 v2.8h,\{v4.16b\},v8\[5\]'
+[^ :]+:[0-9]+: Info:    did you mean this\?
+[^ :]+:[0-9]+: Info:    	luti4 v2.16b, \{v4.16b\}, v8\[5\]
+[^ :]+:[0-9]+: Error: missing braces at operand 2 -- `luti2 v2.16b,v4.16b,v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected a vector register at operand 1 -- `luti2 x12,\{v4.16b\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected an Advanced SIMD vector register at operand 2 -- `luti2 v2.16b,\{x12\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: operand 3 must be a SIMD vector without a type qualifier encoding a bit index -- `luti2 v2.16b,\{v4.16b\},x12\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: missing braces at operand 2 -- `luti2 v2.8h,v4.8h,v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected a vector register at operand 1 -- `luti2 x12,\{v4.8h\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected an Advanced SIMD vector register at operand 2 -- `luti2 v2.8h,\{x12\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: operand 3 must be a SIMD vector without a type qualifier encoding a bit index -- `luti2 v2.8h,\{v4.8h\},x12\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: missing braces at operand 2 -- `luti4 v2.16b,v4.16b,v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected a vector register at operand 1 -- `luti4 x12,\{v4.16b\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected an Advanced SIMD vector register at operand 2 -- `luti4 v2.16b,\{x12\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: operand 3 must be a SIMD vector without a type qualifier encoding a bit index -- `luti4 v2.16b,\{v4.16b\},x12\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: missing braces at operand 2 -- `luti4 v2.8h,v4.8h,v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected a vector register at operand 1 -- `luti4 x12,\{v4.8h\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected an Advanced SIMD vector register at operand 2 -- `luti4 v2.8h,\{x12\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: operand 3 must be a SIMD vector without a type qualifier encoding a bit index -- `luti4 v2.8h,\{v4.8h\},x12\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: operand 2 must be a SIMD vector register list -- `luti4 v2.8h,\{v4.8h,x12\},v8\[1\]'
+[^ :]+:[0-9]+: Error: operand mismatch -- `luti2 v2.8b,\{v4.8b\},v8\[1\]'
+[^ :]+:[0-9]+: Info:    did you mean this\?
+[^ :]+:[0-9]+: Info:    	luti2 v2.16b, \{v4.16b\}, v8\[1\]
+[^ :]+:[0-9]+: Error: operand mismatch -- `luti2 v2.4h,\{v4.4h\},v8\[1\]'
+[^ :]+:[0-9]+: Info:    did you mean this\?
+[^ :]+:[0-9]+: Info:    	luti2 v2.16b, \{v4.16b\}, v8\[1\]
+[^ :]+:[0-9]+: Error: operand mismatch -- `luti4 v2.8b,\{v4.8b\},v8\[5\]'
+[^ :]+:[0-9]+: Info:    did you mean this\?
+[^ :]+:[0-9]+: Info:    	luti4 v2.16b, \{v4.16b\}, v8\[5\]
+[^ :]+:[0-9]+: Error: operand mismatch -- `luti4 v2.4h,\{v4.4h,v5.4h\},v8\[5\]'
+[^ :]+:[0-9]+: Info:    did you mean this\?
+[^ :]+:[0-9]+: Info:    	luti4 v2.16b, \{v4.16b-v5.16b\}, v8\[5\]
+[^ :]+:[0-9]+: Error: comma expected between operands at operand 2 -- `luti2 v2.16b'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected element type rather than vector type at operand 2 -- `luti2 v2.16b,\{v4.16b\}'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: unexpected characters following instruction at operand 3 -- `luti2 v2.16b,\{v4.16b\},v8\[1\],v16.16b'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: unexpected characters following instruction at operand 3 -- `luti2 v2.16b,\{v4.16b\},v8\[1\],\{v16.16b\}'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: comma expected between operands at operand 2 -- `luti2 v2.8h'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected element type rather than vector type at operand 2 -- `luti2 v2.8h,\{v4.8h\}'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: unexpected characters following instruction at operand 3 -- `luti2 v2.8h,\{v4.8h\},v8\[1\],v16.8h'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: unexpected characters following instruction at operand 3 -- `luti2 v2.8h,\{v4.8h\},v8\[1\],\{v16.8h\}'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: comma expected between operands at operand 2 -- `luti4 v2.16b'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected element type rather than vector type at operand 2 -- `luti4 v2.16b,\{v4.16b\}'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: unexpected characters following instruction at operand 3 -- `luti4 v2.16b,\{v4.16b\},v8\[1\],v16.16b'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: unexpected characters following instruction at operand 3 -- `luti4 v2.16b,\{v4.16b\},v8\[1\],\{v16.16b\}'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: comma expected between operands at operand 2 -- `luti4 v2.8h'
+[^ :]+:[0-9]+: Error: expected element type rather than vector type at operand 2 -- `luti4 v2.8h,\{v4.8h,v5.8h\}'
+[^ :]+:[0-9]+: Error: unexpected characters following instruction at operand 3 -- `luti4 v2.8h,\{v4.8h,v5.8h\},v8\[1\],v16.8h'
+[^ :]+:[0-9]+: Error: unexpected characters following instruction at operand 3 -- `luti4 v2.8h,\{v4.8h,v5.8h\},v8\[1\],\{v16.8h\}'
+[^ :]+:[0-9]+: Error: unexpected character `t' in element size at operand 2 -- `luti2 v2.16b,\{v4.16t\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: unexpected character `t' in element size at operand 1 -- `luti2 v2.16t,\{v4.16b\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: unexpected character `m' in element size at operand 2 -- `luti2 v2.8h,\{v4.8m\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: unexpected character `m' in element size at operand 1 -- `luti2 v2.8m,\{v4.8h\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: unexpected character `t' in element size at operand 2 -- `luti4 v2.16b,\{v4.16t\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: unexpected character `t' in element size at operand 1 -- `luti4 v2.16t,\{v4.16b\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: unexpected character `t' in element size at operand 2 -- `luti4 v2.8h,\{v4.8h,v5.8t\},v8\[1\]'
+[^ :]+:[0-9]+: Error: unexpected character `t' in element size at operand 1 -- `luti4 v2.8t,\{v4.8h,v5.8h\},v8\[1\]'
+[^ :]+:[0-9]+: Error: invalid use of vector register at operand 2 -- `luti2 v2.16b,\{v4\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: invalid use of vector register at operand 1 -- `luti2 v2,\{v4.16b\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected a register or register list at operand 1 -- `luti2 2.16b,\{v4.16b\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: syntax error in register list at operand 2 -- `luti2 v2.16b,\{4.16b\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: invalid use of vector register at operand 2 -- `luti2 v2.8h,\{v4\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: invalid use of vector register at operand 1 -- `luti2 v2,\{v4.8h\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected a register or register list at operand 1 -- `luti2 2.8h,\{v4.8h\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: syntax error in register list at operand 2 -- `luti2 v2.8h,\{4.8h\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: invalid use of vector register at operand 2 -- `luti4 v2.16b,\{v4\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: invalid use of vector register at operand 1 -- `luti4 v2,\{v4.16b\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected a register or register list at operand 1 -- `luti4 2.16b,\{v4.16b\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: syntax error in register list at operand 2 -- `luti4 v2.16b,\{4.16b\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: invalid use of vector register at operand 2 -- `luti4 v2.16b,\{v4,v5.16b\},v8\[1\]'
+[^ :]+:[0-9]+: Error: invalid use of vector register at operand 1 -- `luti4 v2,\{v4.16b,v5.16b\},v8\[1\]'
+[^ :]+:[0-9]+: Error: expected a register or register list at operand 1 -- `luti4 2.16b,\{v4.16b,v5.16b\},v8\[1\]'
+[^ :]+:[0-9]+: Error: syntax error in register list at operand 2 -- `luti4 v2.16b,\{v4.16b,5.16b\},v8\[1\]'
+[^ :]+:[0-9]+: Error: operand 3 must be a SIMD vector without a type qualifier encoding a bit index -- `luti2 v17.16b,\{v21.16b\},v27.16b\[3\]'
+[^ :]+:[0-9]+: Error: operand 3 must be a SIMD vector without a type qualifier encoding a bit index -- `luti2 v17.8h,\{v21.8h\},v27.8h\[4\]'
+[^ :]+:[0-9]+: Error: operand 3 must be a SIMD vector without a type qualifier encoding a bit index -- `luti4 v17.16b,\{v21.16b\},v27.16b\[1\]'
+[^ :]+:[0-9]+: Error: operand 3 must be a SIMD vector without a type qualifier encoding a bit index -- `luti4 v17.8h,\{v21.8h,v22.8h\},v27.8h\[2\]'
+[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 1 -- `luti2 v17.16b\[1\],\{v0.16b\},v31.16b'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: this type of register can't be indexed at operand 1 -- `luti2 v17\[1\],\{v0.16b\},v31.16b'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: index not allowed inside register list at operand 2 -- `luti2 v17.16b,\{v0.16b\[1\]\},v31.16b'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: this type of register can't be indexed at operand 2 -- `luti2 v17.16b,\{v0\[1\]\},v31.16b'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 1 -- `luti2 v17.8h\[1\],\{v0.8h\},v31.8h'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: this type of register can't be indexed at operand 1 -- `luti2 v17\[1\],\{v0.8h\},v31.8h'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: index not allowed inside register list at operand 2 -- `luti2 v17.8h,\{v0.8h\[1\]\},v31.8h'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: this type of register can't be indexed at operand 2 -- `luti2 v17.8h,\{v0\[1\]\},v31.8h'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 1 -- `luti4 v17.16b\[1\],\{v0.16b\},v31.16b'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: this type of register can't be indexed at operand 1 -- `luti4 v17\[1\],\{v0.16b\},v31.16b'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: index not allowed inside register list at operand 2 -- `luti4 v17.16b,\{v0.16b\[1\]\},v31.16b'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: this type of register can't be indexed at operand 2 -- `luti4 v17.16b,\{v0\[1\]\},v31.16b'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 1 -- `luti4 v17.8h\[1\],\{v0.8h,v1.8h\},v31.8h'
+[^ :]+:[0-9]+: Error: this type of register can't be indexed at operand 1 -- `luti4 v17\[1\],\{v0.8h,v1.8h\},v31.8h'
+[^ :]+:[0-9]+: Error: index not allowed inside register list at operand 2 -- `luti4 v17.8h,\{v0.8h\[1\],v1.8h\},v31.8h'
+[^ :]+:[0-9]+: Error: this type of register can't be indexed at operand 2 -- `luti4 v17.8h,\{v0\[1\],v1.8h\},v31.8h'
+[^ :]+:[0-9]+: Error: operand 3 must be a SIMD vector without a type qualifier encoding a bit index -- `luti2 v2.16b,\{v4.16b\},v8.16b'
+[^ :]+:[0-9]+: Error: operand 3 must be a SIMD vector without a type qualifier encoding a bit index -- `luti2 v2.16b,\{v4.16b\},v8'
+[^ :]+:[0-9]+: Error: operand 3 must be a SIMD vector without a type qualifier encoding a bit index -- `luti2 v2.8h,\{v4.8h\},v8.8h'
+[^ :]+:[0-9]+: Error: operand 3 must be a SIMD vector without a type qualifier encoding a bit index -- `luti2 v2.8h,\{v4.8h\},v8'
+[^ :]+:[0-9]+: Error: operand 3 must be a SIMD vector without a type qualifier encoding a bit index -- `luti4 v2.16b,\{v4.16b\},v8.16b'
+[^ :]+:[0-9]+: Error: operand 3 must be a SIMD vector without a type qualifier encoding a bit index -- `luti4 v2.16b,\{v4.16b\},v8'
+[^ :]+:[0-9]+: Error: operand 3 must be a SIMD vector without a type qualifier encoding a bit index -- `luti4 v2.8h,\{v4.8h,v5.8h\},v8.8h'
+[^ :]+:[0-9]+: Error: operand 3 must be a SIMD vector without a type qualifier encoding a bit index -- `luti4 v2.8h,\{v4.8h,v5.8h\},v8'
+[^ :]+:[0-9]+: Error: expected a register or register list at operand 1 -- `luti2 v32.16b,\{v4.16b\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected an Advanced SIMD vector register at operand 2 -- `luti2 v2.16b,\{v32.16b\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: operand 3 must be a SIMD vector without a type qualifier encoding a bit index -- `luti2 v2.16b,\{v4.16b\},v32\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: register element index out of range 0 to 3 at operand 3 -- `luti2 v2.16b,\{v4.16b\},v8\[4\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: register element index out of range 0 to 3 at operand 3 -- `luti2 v2.16b,\{v4.16b\},v8\[-1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected a register or register list at operand 1 -- `luti2 v32.8h,\{v4.8h\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected an Advanced SIMD vector register at operand 2 -- `luti2 v2.8h,\{v32.8h\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: operand 3 must be a SIMD vector without a type qualifier encoding a bit index -- `luti2 v2.8h,\{v4.8h\},v32\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: register element index out of range 0 to 7 at operand 3 -- `luti2 v2.8h,\{v4.8h\},v8\[8\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: register element index out of range 0 to 7 at operand 3 -- `luti2 v2.8h,\{v4.8h\},v8\[-1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected a register or register list at operand 1 -- `luti4 v32.16b,\{v4.16b\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected an Advanced SIMD vector register at operand 2 -- `luti4 v2.16b,\{v32.16b\},v8\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: operand 3 must be a SIMD vector without a type qualifier encoding a bit index -- `luti4 v2.16b,\{v4.16b\},v32\[1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: register element index out of range 0 to 1 at operand 3 -- `luti4 v2.16b,\{v4.16b\},v8\[2\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: register element index out of range 0 to 1 at operand 3 -- `luti4 v2.16b,\{v4.16b\},v8\[-1\]'
+[^ :]+:[0-9]+:  Info: macro invoked from here
+[^ :]+:[0-9]+: Error: expected a register or register list at operand 1 -- `luti4 v32.8h,\{v4.8h,v5.8h\},v8\[1\]'
+[^ :]+:[0-9]+: Error: operand 2 must be a SIMD vector register list -- `luti4 v2.8h,\{v31.8h,v32.8h\},v8\[1\]'
+[^ :]+:[0-9]+: Error: operand 3 must be a SIMD vector without a type qualifier encoding a bit index -- `luti4 v2.8h,\{v4.8h,v5.8h\},v32\[1\]'
+[^ :]+:[0-9]+: Error: register element index out of range 0 to 3 at operand 3 -- `luti4 v2.8h,\{v4.8h,v5.8h\},v8\[4\]'
+[^ :]+:[0-9]+: Error: register element index out of range 0 to 3 at operand 3 -- `luti4 v2.8h,\{v4.8h,v5.8h\},v8\[-1\]'
+[^ :]+:[0-9]+: Error: the register list must have a stride of 1 at operand 2 -- `luti4 v2.8h,\{v4.8h,v6.8h\},v8\[2\]'
+[^ :]+:[0-9]+: Error: expected a single-register list at operand 2 -- `luti2 v17.16b,\{v21.16b,v22.16b\},v27\[2\]'
+[^ :]+:[0-9]+: Error: expected a single-register list at operand 2 -- `luti2 v17.8h,\{v21.8h,v22.8h\},v27\[4\]'
+[^ :]+:[0-9]+: Error: expected a single-register list at operand 2 -- `luti4 v17.16b,\{v21.16b,v22.16b\},v27\[1\]'
+[^ :]+:[0-9]+: Error: expected a list of 2 registers at operand 2 -- `luti4 v17.8h,\{v21.8h\},v27\[2\]'
diff --git a/gas/testsuite/gas/aarch64/advsimd-lut-illegal.s b/gas/testsuite/gas/aarch64/advsimd-lut-illegal.s
new file mode 100644
index 00000000000..24771fa1474
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/advsimd-lut-illegal.s
@@ -0,0 +1,128 @@ 
+	// Operand mismatch
+	luti2	v2.16b, { v4.8h }, v8[1]
+	luti2	v2.8h, { v4.16b }, v8[1]
+	luti4	v2.16b, { v4.8h }, v8[5]
+	luti4	v2.8h, { v4.16b }, v8[5]
+
+	// Incorrect operand types
+	.macro incorrect_operand_types op, operand_type
+	\op	v2\operand_type, v4\operand_type, v8[1]
+	\op	x12, { v4\operand_type }, v8[1]
+	\op	v2\operand_type, { x12 }, v8[1]
+	\op	v2\operand_type, { v4\operand_type }, x12[1]
+	.endm
+
+	incorrect_operand_types luti2 .16b
+	incorrect_operand_types luti2 .8h
+	incorrect_operand_types luti4 .16b
+	incorrect_operand_types luti4 .8h
+	luti4	v2.8h, { v4.8h, x12 }, v8[1]
+
+	// Disallowed types
+	luti2	v2.8b, { v4.8b }, v8[1]
+	luti2	v2.4h, { v4.4h }, v8[1]
+	luti4	v2.8b, { v4.8b }, v8[5]
+	luti4	v2.4h, { v4.4h, v5.4h }, v8[5]
+
+	// Incorrect number of operands
+	.macro 	incorrect_operands, op, operand_type
+	\op	v2\operand_type
+	\op	v2\operand_type, { v4\operand_type }
+	\op	v2\operand_type, { v4\operand_type }, v8[1], v16\operand_type
+	\op	v2\operand_type, { v4\operand_type }, v8[1], { v16\operand_type }
+	.endm
+
+	incorrect_operands luti2 .16b
+	incorrect_operands luti2 .8h
+	incorrect_operands luti4 .16b
+	luti4	v2.8h
+	luti4	v2.8h, { v4.8h, v5.8h }
+	luti4	v2.8h, { v4.8h, v5.8h }, v8[1], v16.8h
+	luti4	v2.8h, { v4.8h, v5.8h }, v8[1], { v16.8h }
+
+	// Spelling mistakes
+	.macro 	spelling_mistakes, op, operand_type, incorrect_operand_type
+	\op	v2\operand_type, { v4\incorrect_operand_type }, v8[1]
+	\op	v2\incorrect_operand_type, { v4\operand_type }, v8[1]
+	.endm
+
+	spelling_mistakes luti2, .16b, .16t
+	spelling_mistakes luti2, .8h, .8m
+	spelling_mistakes luti4, .16b, .16t
+	luti4	v2.8h, { v4.8h, v5.8t }, v8[1]
+	luti4	v2.8t, { v4.8h, v5.8h }, v8[1]
+
+	// Missing qualifiers
+	.macro	missing_qualifiers, op, operand_type
+	\op	v2\operand_type, { v4 }, v8[1]
+	\op	v2, { v4\operand_type }, v8[1]
+	\op	2\operand_type, { v4\operand_type }, v8[1]
+	\op	v2\operand_type, { 4\operand_type }, v8[1]
+	.endm
+
+	missing_qualifiers luti2, .16b
+	missing_qualifiers luti2, .8h
+	missing_qualifiers luti4, .16b
+	luti4	v2.16b, { v4, v5.16b }, v8[1]
+	luti4	v2, { v4.16b, v5.16b }, v8[1]
+	luti4	2.16b, { v4.16b, v5.16b }, v8[1]
+	luti4	v2.16b, { v4.16b, 5.16b }, v8[1]
+
+	// Index with qualifiers
+	luti2	v17.16b, { v21.16b }, v27.16b[3]
+	luti2	v17.8h, { v21.8h }, v27.8h[4]
+	luti4	v17.16b, { v21.16b }, v27.16b[1]
+	luti4	v17.8h, { v21.8h, v22.8h }, v27.8h[2]
+
+	// Index on the wrong operand
+	.macro index_wrong_operand, op, operand_type
+	\op	v17\operand_type[1], { v0\operand_type }, v31\operand_type
+	\op	v17[1], { v0\operand_type }, v31\operand_type
+	\op	v17\operand_type, { v0\operand_type[1] }, v31\operand_type
+	\op	v17\operand_type, { v0[1] }, v31\operand_type
+	.endm
+
+	index_wrong_operand luti2, .16b
+	index_wrong_operand luti2, .8h
+	index_wrong_operand luti4, .16b
+	luti4	v17.8h[1], { v0.8h, v1.8h }, v31.8h
+	luti4	v17[1], { v0.8h, v1.8h }, v31.8h
+	luti4	v17.8h, { v0.8h[1], v1.8h }, v31.8h
+	luti4	v17.8h, { v0[1], v1.8h }, v31.8h
+
+	// Missing index
+	luti2	v2.16b, { v4.16b }, v8.16b
+	luti2	v2.16b, { v4.16b }, v8
+	luti2	v2.8h, { v4.8h }, v8.8h
+	luti2	v2.8h, { v4.8h }, v8
+	luti4	v2.16b, { v4.16b }, v8.16b
+	luti4	v2.16b, { v4.16b }, v8
+	luti4	v2.8h, { v4.8h, v5.8h }, v8.8h
+	luti4	v2.8h, { v4.8h, v5.8h }, v8
+
+	// Out of range operands
+	.macro	out_of_range, op, operand_type, max_index_plus_one
+	\op	v32\operand_type, { v4\operand_type }, v8[1]
+	\op	v2\operand_type, { v32\operand_type }, v8[1]
+	\op	v2\operand_type, { v4\operand_type }, v32[1]
+	\op	v2\operand_type, { v4\operand_type }, v8[\max_index_plus_one]
+	\op	v2\operand_type, { v4\operand_type }, v8[-1]
+	.endm
+
+	out_of_range luti2, .16b, 4
+	out_of_range luti2, .8h, 8
+	out_of_range luti4, .16b, 2
+	luti4	v32.8h, { v4.8h, v5.8h }, v8[1]
+	luti4	v2.8h, { v31.8h, v32.8h }, v8[1]
+	luti4	v2.8h, { v4.8h, v5.8h }, v32[1]
+	luti4	v2.8h, { v4.8h, v5.8h }, v8[4]
+	luti4	v2.8h, { v4.8h, v5.8h }, v8[-1]
+
+	// Incorrect stride of operand
+	luti4	v2.8h, { v4.8h, v6.8h }, v8[2]
+
+	// Incorrect operands
+	luti2	v17.16b, { v21.16b, v22.16b }, v27[2]
+	luti2	v17.8h, { v21.8h, v22.8h }, v27[4]
+	luti4	v17.16b, { v21.16b, v22.16b }, v27[1]
+	luti4	v17.8h, { v21.8h }, v27[2]
diff --git a/gas/testsuite/gas/aarch64/advsimd-lut.d b/gas/testsuite/gas/aarch64/advsimd-lut.d
new file mode 100644
index 00000000000..0240d0ded6d
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/advsimd-lut.d
@@ -0,0 +1,32 @@ 
+#objdump: -dr
+#as: -march=armv8-a+lut
+
+.*:     file format .*
+
+Disassembly of section \.text:
+
+0+ <.*>:
+[^:]+:	4e801000 	luti2	v0.16b, \{v0.16b\}, v0\[0\]
+[^:]+:	4e80101f 	luti2	v31.16b, \{v0.16b\}, v0\[0\]
+[^:]+:	4e8013e0 	luti2	v0.16b, \{v31.16b\}, v0\[0\]
+[^:]+:	4e9f1000 	luti2	v0.16b, \{v0.16b\}, v31\[0\]
+[^:]+:	4e9f7000 	luti2	v0.16b, \{v0.16b\}, v31\[3\]
+[^:]+:	4e9b52b1 	luti2	v17.16b, \{v21.16b\}, v27\[2\]
+[^:]+:	4ec00000 	luti2	v0.8h, \{v0.8h\}, v0\[0\]
+[^:]+:	4ec0001f 	luti2	v31.8h, \{v0.8h\}, v0\[0\]
+[^:]+:	4ec003e0 	luti2	v0.8h, \{v31.8h\}, v0\[0\]
+[^:]+:	4edf0000 	luti2	v0.8h, \{v0.8h\}, v31\[0\]
+[^:]+:	4ec07000 	luti2	v0.8h, \{v0.8h\}, v0\[7\]
+[^:]+:	4edb42b1 	luti2	v17.8h, \{v21.8h\}, v27\[4\]
+[^:]+:	4e402000 	luti4	v0.16b, \{v0.16b\}, v0\[0\]
+[^:]+:	4e40201f 	luti4	v31.16b, \{v0.16b\}, v0\[0\]
+[^:]+:	4e4023e0 	luti4	v0.16b, \{v31.16b\}, v0\[0\]
+[^:]+:	4e5f2000 	luti4	v0.16b, \{v0.16b\}, v31\[0\]
+[^:]+:	4e406000 	luti4	v0.16b, \{v0.16b\}, v0\[1\]
+[^:]+:	4e5b62b1 	luti4	v17.16b, \{v21.16b\}, v27\[1\]
+[^:]+:	4e401000 	luti4	v0.8h, \{v0.8h-v1.8h\}, v0\[0\]
+[^:]+:	4e40101f 	luti4	v31.8h, \{v0.8h-v1.8h\}, v0\[0\]
+[^:]+:	4e4013e0 	luti4	v0.8h, \{v31.8h-v0.8h\}, v0\[0\]
+[^:]+:	4e5f1000 	luti4	v0.8h, \{v0.8h-v1.8h\}, v31\[0\]
+[^:]+:	4e407000 	luti4	v0.8h, \{v0.8h-v1.8h\}, v0\[3\]
+[^:]+:	4e5b52b1 	luti4	v17.8h, \{v21.8h-v22.8h\}, v27\[2\]
diff --git a/gas/testsuite/gas/aarch64/advsimd-lut.s b/gas/testsuite/gas/aarch64/advsimd-lut.s
new file mode 100644
index 00000000000..03bc27ab2ab
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/advsimd-lut.s
@@ -0,0 +1,29 @@ 
+	// Valid luti2 instructions
+	luti2	v0.16b, { v0.16b }, v0[0]
+	luti2	v31.16b, { v0.16b }, v0[0]
+	luti2	v0.16b, { v31.16b }, v0[0]
+	luti2	v0.16b, { v0.16b }, v31[0]
+	luti2	v0.16b, { v0.16b }, v31[3]
+	luti2	v17.16b, { v21.16b }, v27[2]
+
+	luti2	v0.8h, { v0.8h }, v0[0]
+	luti2	v31.8h, { v0.8h }, v0[0]
+	luti2	v0.8h, { v31.8h }, v0[0]
+	luti2	v0.8h, { v0.8h }, v31[0]
+	luti2	v0.8h, { v0.8h }, v0[7]
+	luti2	v17.8h, { v21.8h }, v27[4]
+
+	// Valid luti4 instructions
+	luti4	v0.16b, { v0.16b }, v0[0]
+	luti4	v31.16b, { v0.16b }, v0[0]
+	luti4	v0.16b, { v31.16b }, v0[0]
+	luti4	v0.16b, { v0.16b }, v31[0]
+	luti4	v0.16b, { v0.16b }, v0[1]
+	luti4	v17.16b, { v21.16b }, v27[1]
+
+	luti4	v0.8h, { v0.8h, v1.8h }, v0[0]
+	luti4	v31.8h, { v0.8h, v1.8h }, v0[0]
+	luti4	v0.8h, { v31.8h, v0.8h }, v0[0]
+	luti4	v0.8h, { v0.8h, v1.8h }, v31[0]
+	luti4	v0.8h, { v0.8h, v1.8h }, v0[3]
+	luti4	v17.8h, { v21.8h, v22.8h }, v27[2]
diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h
index ef4a3ffdcd3..95448b58721 100644
--- a/include/opcode/aarch64.h
+++ b/include/opcode/aarch64.h
@@ -236,6 +236,8 @@  enum aarch64_feature_bit {
   AARCH64_FEATURE_FAMINMAX,
   /* FP8 instructions.  */
   AARCH64_FEATURE_FP8,
+  /* LUT instructions.  */
+  AARCH64_FEATURE_LUT,
   AARCH64_NUM_FEATURES
 };
 
@@ -523,10 +525,14 @@  enum aarch64_opnd
   AARCH64_OPND_Em,	/* AdvSIMD Vector Element Vm.  */
   AARCH64_OPND_Em16,	/* AdvSIMD Vector Element Vm restricted to V0 - V15 when
 			   qualifier is S_H.  */
+  AARCH64_OPND_Em_INDEX1_14,  /* AdvSIMD 1-bit encoded index in Vm at [14]  */
+  AARCH64_OPND_Em_INDEX2_13,  /* AdvSIMD 2-bit encoded index in Vm at [14:13]  */
+  AARCH64_OPND_Em_INDEX3_12,  /* AdvSIMD 3-bit encoded index in Vm at [14:12]  */
   AARCH64_OPND_LVn,	/* AdvSIMD Vector register list used in e.g. TBL.  */
   AARCH64_OPND_LVt,	/* AdvSIMD Vector register list used in ld/st.  */
   AARCH64_OPND_LVt_AL,	/* AdvSIMD Vector register list for loading single
 			   structure to all lanes.  */
+  AARCH64_OPND_LVn_LUT,	/* AdvSIMD Vector register list used in lut.  */
   AARCH64_OPND_LEt,	/* AdvSIMD Vector Element list.  */
 
   AARCH64_OPND_CRn,	/* Co-processor register in CRn field.  */
@@ -1026,7 +1032,8 @@  enum aarch64_insn_class
   the,
   sve2_urqvs,
   sve_index1,
-  rcpc3
+  rcpc3,
+  lut
 };
 
 /* Opcode enumerators.  */
diff --git a/opcodes/aarch64-asm.c b/opcodes/aarch64-asm.c
index 5a55ca2f86d..338ed54165d 100644
--- a/opcodes/aarch64-asm.c
+++ b/opcodes/aarch64-asm.c
@@ -168,6 +168,27 @@  aarch64_ins_reglane (const aarch64_operand *self, const aarch64_opnd_info *info,
       assert (reglane_index < 4);
       insert_field (FLD_SM3_imm2, code, reglane_index, 0);
     }
+  else if (inst->opcode->iclass == lut)
+    {
+      unsigned reglane_index = info->reglane.index;
+      switch (info->type)
+	{
+	case AARCH64_OPND_Em_INDEX1_14:
+	  assert (reglane_index < 2);
+	  insert_field (FLD_imm1_14, code, reglane_index, 0);
+	  break;
+	case AARCH64_OPND_Em_INDEX2_13:
+	  assert (reglane_index < 4);
+	  insert_field (FLD_imm2_13, code, reglane_index, 0);
+	  break;
+	case AARCH64_OPND_Em_INDEX3_12:
+	  assert (reglane_index < 8);
+	  insert_field (FLD_imm3_12, code, reglane_index, 0);
+	  break;
+	default:
+	  return false;
+	}
+    }
   else
     {
       /* index for e.g. SQDMLAL <Va><d>, <Vb><n>, <Vm>.<Ts>[<index>]
@@ -286,6 +307,17 @@  aarch64_ins_ldst_reglist_r (const aarch64_operand *self ATTRIBUTE_UNUSED,
   return true;
 }
 
+/* Insert regnos of register list operand for AdvSIMD lut instructions.  */
+bool
+aarch64_ins_lut_reglist (const aarch64_operand *self, const aarch64_opnd_info *info,
+		     aarch64_insn *code,
+		     const aarch64_inst *inst ATTRIBUTE_UNUSED,
+		     aarch64_operand_error *errors ATTRIBUTE_UNUSED)
+{
+  insert_field (self->fields[0], code, info->reglist.first_regno, 0);
+  return true;
+}
+
 /* Insert Q, opcode<2:1>, S, size and Rt fields for a register element list
    operand e.g. Vt in AdvSIMD load/store single element instructions.  */
 bool
diff --git a/opcodes/aarch64-asm.h b/opcodes/aarch64-asm.h
index 88e389bfebd..edeb6d8de7e 100644
--- a/opcodes/aarch64-asm.h
+++ b/opcodes/aarch64-asm.h
@@ -47,6 +47,7 @@  AARCH64_DECL_OPD_INSERTER (ins_reglane);
 AARCH64_DECL_OPD_INSERTER (ins_reglist);
 AARCH64_DECL_OPD_INSERTER (ins_ldst_reglist);
 AARCH64_DECL_OPD_INSERTER (ins_ldst_reglist_r);
+AARCH64_DECL_OPD_INSERTER (ins_lut_reglist);
 AARCH64_DECL_OPD_INSERTER (ins_ldst_elemlist);
 AARCH64_DECL_OPD_INSERTER (ins_advsimd_imm_shift);
 AARCH64_DECL_OPD_INSERTER (ins_imm);
diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c
index e1c3f557874..213df616608 100644
--- a/opcodes/aarch64-dis.c
+++ b/opcodes/aarch64-dis.c
@@ -548,6 +548,21 @@  aarch64_ext_ldst_reglist_r (const aarch64_operand *self ATTRIBUTE_UNUSED,
   return true;
 }
 
+/* Decode AdvSIMD vector register list for AdvSIMD lut instructions.
+   The number of of registers in the list is determined by the opcode
+   flag.  */
+bool
+aarch64_ext_lut_reglist (const aarch64_operand *self, aarch64_opnd_info *info,
+		     const aarch64_insn code,
+		     const aarch64_inst *inst ATTRIBUTE_UNUSED,
+		     aarch64_operand_error *errors ATTRIBUTE_UNUSED)
+{
+  info->reglist.first_regno = extract_field (self->fields[0], code, 0);
+  info->reglist.num_regs = get_opcode_dependent_value (inst->opcode);
+  info->reglist.stride = 1;
+  return true;
+}
+
 /* Decode Q, opcode<2:1>, S, size and Rt fields of Vt in AdvSIMD
    load/store single element instructions.  */
 bool
diff --git a/opcodes/aarch64-dis.h b/opcodes/aarch64-dis.h
index 86494cc3093..9e8f7c214d7 100644
--- a/opcodes/aarch64-dis.h
+++ b/opcodes/aarch64-dis.h
@@ -70,6 +70,7 @@  AARCH64_DECL_OPD_EXTRACTOR (ext_reglane);
 AARCH64_DECL_OPD_EXTRACTOR (ext_reglist);
 AARCH64_DECL_OPD_EXTRACTOR (ext_ldst_reglist);
 AARCH64_DECL_OPD_EXTRACTOR (ext_ldst_reglist_r);
+AARCH64_DECL_OPD_EXTRACTOR (ext_lut_reglist);
 AARCH64_DECL_OPD_EXTRACTOR (ext_ldst_elemlist);
 AARCH64_DECL_OPD_EXTRACTOR (ext_advsimd_imm_shift);
 AARCH64_DECL_OPD_EXTRACTOR (ext_shll_imm);
diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
index 032ab17e250..84a3955b83b 100644
--- a/opcodes/aarch64-opc.c
+++ b/opcodes/aarch64-opc.c
@@ -337,6 +337,7 @@  const aarch64_field fields[] =
     {  2,  1 },	/* imm1_2: general immediate in bits [2].  */
     {  8,  1 },	/* imm1_8: general immediate in bits [8].  */
     { 10,  1 },	/* imm1_10: general immediate in bits [10].  */
+    { 14,  1 },	/* imm1_14: general immediate in bits [14].  */
     { 15,  1 },	/* imm1_15: general immediate in bits [15].  */
     { 16,  1 },	/* imm1_16: general immediate in bits [16].  */
     {  0,  2 },	/* imm2_0: general immediate in bits [1:0].  */
@@ -344,6 +345,7 @@  const aarch64_field fields[] =
     {  8,  2 },	/* imm2_8: general immediate in bits [9:8].  */
     { 10,  2 }, /* imm2_10: 2-bit immediate, bits [11:10] */
     { 12,  2 }, /* imm2_12: 2-bit immediate, bits [13:12] */
+    { 13,  2 }, /* imm2_13: 2-bit immediate, bits [14:13] */
     { 15,  2 }, /* imm2_15: 2-bit immediate, bits [16:15] */
     { 16,  2 }, /* imm2_16: 2-bit immediate, bits [17:16] */
     { 19,  2 }, /* imm2_19: 2-bit immediate, bits [20:19] */
@@ -2554,6 +2556,10 @@  operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
       num = get_opcode_dependent_value (opcode);
       switch (type)
 	{
+	case AARCH64_OPND_LVn_LUT:
+	  if (!check_reglist (opnd, mismatch_detail, idx, num, 1))
+	    return 0;
+	  break;
 	case AARCH64_OPND_LVt:
 	  assert (num >= 1 && num <= 4);
 	  /* Unless LD1/ST1, the number of registers should be equal to that
@@ -3165,6 +3171,14 @@  operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
 	   and is halfed because complex numbers take two elements.  */
 	num = aarch64_get_qualifier_nelem (opnds[0].qualifier)
 	      * aarch64_get_qualifier_esize (opnds[0].qualifier) / 2;
+      else if (opcode->iclass == lut)
+	{
+	  size = get_operand_fields_width (get_operand_from_code (type)) - 5;
+	  if (!check_reglane (opnd, mismatch_detail, idx, "v", 0, 31,
+			      0, (1 << size) - 1))
+	    return 0;
+	  break;
+	}
       else
 	num = 16;
       num = num / aarch64_get_qualifier_esize (qualifier) - 1;
@@ -4069,6 +4083,14 @@  aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
 		style_imm (styler, "%" PRIi64, opnd->reglane.index));
       break;
 
+    case AARCH64_OPND_Em_INDEX1_14:
+    case AARCH64_OPND_Em_INDEX2_13:
+    case AARCH64_OPND_Em_INDEX3_12:
+      snprintf (buf, size, "%s[%s]",
+		style_reg (styler, "v%d", opnd->reglane.regno),
+		style_imm (styler, "%" PRIi64, opnd->reglane.index));
+      break;
+
     case AARCH64_OPND_VdD1:
     case AARCH64_OPND_VnD1:
       snprintf (buf, size, "%s[%s]",
@@ -4077,6 +4099,7 @@  aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
       break;
 
     case AARCH64_OPND_LVn:
+    case AARCH64_OPND_LVn_LUT:
     case AARCH64_OPND_LVt:
     case AARCH64_OPND_LVt_AL:
     case AARCH64_OPND_LEt:
diff --git a/opcodes/aarch64-opc.h b/opcodes/aarch64-opc.h
index 4e781f000cc..23e634f1250 100644
--- a/opcodes/aarch64-opc.h
+++ b/opcodes/aarch64-opc.h
@@ -147,6 +147,7 @@  enum aarch64_field_kind
   FLD_imm1_2,
   FLD_imm1_8,
   FLD_imm1_10,
+  FLD_imm1_14,
   FLD_imm1_15,
   FLD_imm1_16,
   FLD_imm2_0,
@@ -154,6 +155,7 @@  enum aarch64_field_kind
   FLD_imm2_8,
   FLD_imm2_10,
   FLD_imm2_12,
+  FLD_imm2_13,
   FLD_imm2_15,
   FLD_imm2_16,
   FLD_imm2_19,
diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h
index 063343dceee..6b98a1bc22d 100644
--- a/opcodes/aarch64-tbl.h
+++ b/opcodes/aarch64-tbl.h
@@ -1004,6 +1004,24 @@ 
   QLF3(V_16B, V_16B, V_16B),	\
 }
 
+/* e.g. luti2 <Vd>.16B, { <Vn>.16B }, <Vm>[index].  */
+/* The third operand is an AdvSIMD vector with a bit index
+   and without a type qualifier and is checked separately
+   based on operand enum.  */
+#define QL_VVUB			\
+{				\
+  QLF3(V_16B , V_16B , NIL),	\
+}
+
+/* e.g. luti2 <Vd>.8H, { <Vn>.8H }, <Vm>[index].  */
+/* The third operand is an AdvSIMD vector with a bit index
+   and without a type qualifier and is checked separately
+   based on operand enum.  */
+#define QL_VVUH			\
+{				\
+  QLF3(V_8H , V_8H , NIL),	\
+}
+
 /* e.g. EXT <Vd>.<T>, <Vn>.<T>, <Vm>.<T>, #<index>.  */
 #define QL_VEXT			\
 {					\
@@ -2711,7 +2729,8 @@  static const aarch64_feature_set aarch64_feature_fp8_sve2 =
   AARCH64_FEATURES (2, FP8, SVE2);
 static const aarch64_feature_set aarch64_feature_fp8_sme2 =
   AARCH64_FEATURES (2, FP8, SME2);
-
+static const aarch64_feature_set aarch64_feature_lut =
+  AARCH64_FEATURE (LUT);
 
 #define CORE		&aarch64_feature_v8
 #define FP		&aarch64_feature_fp
@@ -2786,6 +2805,7 @@  static const aarch64_feature_set aarch64_feature_fp8_sme2 =
 #define FP8	  &aarch64_feature_fp8
 #define FP8_SVE2   &aarch64_feature_fp8_sve2
 #define FP8_SME2   &aarch64_feature_fp8_sme2
+#define LUT &aarch64_feature_lut
 
 #define CORE_INSN(NAME,OPCODE,MASK,CLASS,OP,OPS,QUALS,FLAGS) \
   { NAME, OPCODE, MASK, CLASS, OP, CORE, OPS, QUALS, FLAGS, 0, 0, NULL }
@@ -2979,6 +2999,8 @@  static const aarch64_feature_set aarch64_feature_fp8_sme2 =
 #define FP8_SME2_INSN(NAME,OPCODE,MASK,CLASS,OP,OPS,QUALS,FLAGS,TIED) \
   { NAME, OPCODE, MASK, CLASS, OP, FP8_SME2, OPS, QUALS,	      \
     F_STRICT | FLAGS, 0, TIED, NULL }
+#define LUT_INSN(NAME,OPCODE,MASK,OPS,QUALS,FLAGS)		\
+  { NAME, OPCODE, MASK, lut, 0, LUT, OPS, QUALS, FLAGS, 0, 0, NULL }
 
 #define MOPS_CPY_OP1_OP2_PME_INSN(NAME, OPCODE, MASK, FLAGS, CONSTRAINTS) \
   MOPS_INSN (NAME, OPCODE, MASK, 0, \
@@ -6551,6 +6573,12 @@  const struct aarch64_opcode aarch64_opcode_table[] =
   CPA_SVE_INSNC ("madpt", 0x44c0d800, 0xffe0fc00, sve_misc, OP3 (SVE_Zd, SVE_Zm_16, SVE_Za_5), OP_SVE_VVV_D, C_SCAN_MOVPRFX, 0),
   CPA_SVE_INSNC ("mlapt", 0x44c0d000, 0xffe0fc00, sve_misc, OP3 (SVE_Zd, SVE_Zn, SVE_Zm_16), OP_SVE_VVV_D, C_SCAN_MOVPRFX, 0),
 
+  /* AdvSIMD lut.  */
+  LUT_INSN ("luti2", 0x4e801000, 0xffe09c00, OP3 (Vd, LVn_LUT, Em_INDEX2_13), QL_VVUB, F_OD(1)),
+  LUT_INSN ("luti2", 0x4ec00000, 0xffe08c00, OP3 (Vd, LVn_LUT, Em_INDEX3_12), QL_VVUH, F_OD(1)),
+  LUT_INSN ("luti4", 0x4e402000, 0xffe0bc00, OP3 (Vd, LVn_LUT, Em_INDEX1_14), QL_VVUB, F_OD(1)),
+  LUT_INSN ("luti4", 0x4e401000, 0xffe09c00, OP3 (Vd, LVn_LUT, Em_INDEX2_13), QL_VVUH, F_OD(2)),
+
   {0, 0, 0, 0, 0, 0, {}, {}, 0, 0, 0, NULL},
 };
 
@@ -6626,12 +6654,20 @@  const struct aarch64_opcode aarch64_opcode_table[] =
       "a SIMD vector element")						\
     Y(SIMD_ELEMENT, reglane, "Em16", 0, F(FLD_Rm),			\
       "a SIMD vector element limited to V0-V15")			\
+    Y(SIMD_ELEMENT, simple_index, "Em_INDEX1_14", 0, F(FLD_Rm, FLD_imm1_14),	\
+      "a SIMD vector without a type qualifier encoding a bit index")	\
+    Y(SIMD_ELEMENT, simple_index, "Em_INDEX2_13", 0, F(FLD_Rm, FLD_imm2_13),	\
+      "a SIMD vector without a type qualifier encoding a bit index")	\
+    Y(SIMD_ELEMENT, simple_index, "Em_INDEX3_12", 0, F(FLD_Rm, FLD_imm3_12),	\
+      "a SIMD vector without a type qualifier encoding a bit index")	\
     Y(SIMD_REGLIST, reglist, "LVn", 0, F(FLD_Rn),			\
       "a SIMD vector register list")					\
     Y(SIMD_REGLIST, ldst_reglist, "LVt", 0, F(),			\
       "a SIMD vector register list")					\
     Y(SIMD_REGLIST, ldst_reglist_r, "LVt_AL", 0, F(),			\
       "a SIMD vector register list")					\
+    Y(SIMD_REGLIST, lut_reglist, "LVn_LUT", 0, F(FLD_Rn),		\
+      "a SIMD vector register list")					\
     Y(SIMD_REGLIST, ldst_elemlist, "LEt", 0, F(),			\
       "a SIMD vector element list")					\
     Y(IMMEDIATE, imm, "CRn", 0, F(FLD_CRn),				\