[llvm] [llvm][AArch64][Assembly]: Add LUT assembly/disassembly. (PR #70802)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Oct 31 06:33:05 PDT 2023
https://github.com/hassnaaHamdi created https://github.com/llvm/llvm-project/pull/70802
This patch adds the feature flags of LUT and SME_LUTv2, and the assembly/disassembly
for the following instructions of NEON, SVE2 and SME2:
* NEON:
- LUT2
- LUT4
* SVE2:
- LUTI2_ZZZI
- LUTI4_ZZZI
- LUTI4_Z2ZZI
* SME:
- MOVT
- LUTI4_4ZZT2Z
- LUTI4_S_4ZZT2Z
That is according to this documentation:
https://developer.arm.com/documentation/ddi0602/2023-09
>From 2f43a61b56c82478899c498d684f4e66e11789e5 Mon Sep 17 00:00:00 2001
From: Hassnaa Hamdi <hassnaa.hamdi at arm.com>
Date: Tue, 31 Oct 2023 13:23:54 +0000
Subject: [PATCH] [llvm][AArch64][Assembly]: Add LUT assembly/disassembly.
This patch adds the feature flags of LUT and SME_LUTv2, and the assembly/disassembly
for the following instructions of NEON, SVE2 and SME2:
* NEON:
- LUT2
- LUT4
* SVE2:
- LUTI2_ZZZI
- LUTI4_ZZZI
- LUTI4_Z2ZZI
* SME:
- MOVT
- LUTI4_4ZZT2Z
- LUTI4_S_4ZZT2Z
That is according to this documentation:
https://developer.arm.com/documentation/ddi0602/2023-09
Change-Id: I10cc46e3fe7efb9f280e26e065b22908d3a0725c
---
.../llvm/TargetParser/AArch64TargetParser.h | 4 ++
.../llvm/TargetParser/SubtargetFeature.h | 2 +-
llvm/lib/Target/AArch64/AArch64.td | 6 ++
.../lib/Target/AArch64/AArch64InstrFormats.td | 48 ++++++++++++++
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 11 ++++
.../lib/Target/AArch64/AArch64RegisterInfo.td | 4 ++
.../lib/Target/AArch64/AArch64SMEInstrInfo.td | 9 +++
.../lib/Target/AArch64/AArch64SVEInstrInfo.td | 9 +++
.../AArch64/AsmParser/AArch64AsmParser.cpp | 16 +++--
.../MCTargetDesc/AArch64InstPrinter.cpp | 4 ++
llvm/lib/Target/AArch64/SMEInstrFormats.td | 52 +++++++++++++++
llvm/lib/Target/AArch64/SVEInstrFormats.td | 52 +++++++++++++++
.../MC/AArch64/FP8/directive-arch-negative.s | 17 +++++
llvm/test/MC/AArch64/FP8/directive-arch.s | 17 ++++-
llvm/test/MC/AArch64/FP8/luti2-diagnostics.s | 37 +++++++++++
llvm/test/MC/AArch64/FP8/luti2.s | 41 ++++++++++++
llvm/test/MC/AArch64/FP8/luti4-diagnostics.s | 50 ++++++++++++++
llvm/test/MC/AArch64/FP8/luti4.s | 41 ++++++++++++
.../MC/AArch64/FP8_SME2/lut-diagnostics.s | 27 ++++++++
llvm/test/MC/AArch64/FP8_SME2/lut.s | 35 ++++++++++
.../MC/AArch64/FP8_SME2/movt-diagnostics.s | 29 +++++++++
llvm/test/MC/AArch64/FP8_SME2/movt.s | 22 +++++++
.../MC/AArch64/FP8_SVE2/luti2-diagnostics.s | 37 +++++++++++
llvm/test/MC/AArch64/FP8_SVE2/luti2.s | 54 +++++++++++++++
.../MC/AArch64/FP8_SVE2/luti4-diagnostics.s | 60 +++++++++++++++++
llvm/test/MC/AArch64/FP8_SVE2/luti4.s | 65 +++++++++++++++++++
.../TargetParser/TargetParserTest.cpp | 45 +++++++------
27 files changed, 766 insertions(+), 28 deletions(-)
create mode 100644 llvm/test/MC/AArch64/FP8/luti2-diagnostics.s
create mode 100644 llvm/test/MC/AArch64/FP8/luti2.s
create mode 100644 llvm/test/MC/AArch64/FP8/luti4-diagnostics.s
create mode 100644 llvm/test/MC/AArch64/FP8/luti4.s
create mode 100644 llvm/test/MC/AArch64/FP8_SME2/lut-diagnostics.s
create mode 100644 llvm/test/MC/AArch64/FP8_SME2/lut.s
create mode 100644 llvm/test/MC/AArch64/FP8_SME2/movt-diagnostics.s
create mode 100644 llvm/test/MC/AArch64/FP8_SME2/movt.s
create mode 100644 llvm/test/MC/AArch64/FP8_SVE2/luti2-diagnostics.s
create mode 100644 llvm/test/MC/AArch64/FP8_SVE2/luti2.s
create mode 100644 llvm/test/MC/AArch64/FP8_SVE2/luti4-diagnostics.s
create mode 100644 llvm/test/MC/AArch64/FP8_SVE2/luti4.s
diff --git a/llvm/include/llvm/TargetParser/AArch64TargetParser.h b/llvm/include/llvm/TargetParser/AArch64TargetParser.h
index 232b3d6a6dbb1c4..5e6b3e9b300e85f 100644
--- a/llvm/include/llvm/TargetParser/AArch64TargetParser.h
+++ b/llvm/include/llvm/TargetParser/AArch64TargetParser.h
@@ -162,6 +162,8 @@ enum ArchExtKind : unsigned {
AEK_FPMR = 58, // FEAT_FPMR
AEK_FP8 = 59, // FEAT_FP8
AEK_FAMINMAX = 60, // FEAT_FAMINMAX
+ AEK_LUT = 61, // FEAT_LUT
+ AEK_SME_LUTv2 = 62, // FEAT_SME_LUTv2
AEK_NUM_EXTENSIONS
};
using ExtensionBitset = Bitset<AEK_NUM_EXTENSIONS>;
@@ -273,6 +275,8 @@ inline constexpr ExtensionInfo Extensions[] = {
{"fpmr", AArch64::AEK_FPMR, "+fpmr", "-fpmr", FEAT_INIT, "", 0},
{"fp8", AArch64::AEK_FP8, "+fp8", "-fp8", FEAT_INIT, "+fpmr", 0},
{"faminmax", AArch64::AEK_FAMINMAX, "+faminmax", "-faminmax", FEAT_INIT, "", 0},
+ {"lut", AArch64::AEK_LUT, "+lut", "-lut", FEAT_INIT, "", 0},
+ {"sme-lutv2", AArch64::AEK_SME_LUTv2, "+sme-lutv2", "-sme-lutv2", FEAT_INIT, "+sme2,+fp8", 0},
// Special cases
{"none", AArch64::AEK_NONE, {}, {}, FEAT_INIT, "", ExtensionInfo::MaxFMVPriority},
};
diff --git a/llvm/include/llvm/TargetParser/SubtargetFeature.h b/llvm/include/llvm/TargetParser/SubtargetFeature.h
index e4dddfb78effbcd..2e1f00dad2df365 100644
--- a/llvm/include/llvm/TargetParser/SubtargetFeature.h
+++ b/llvm/include/llvm/TargetParser/SubtargetFeature.h
@@ -31,7 +31,7 @@ namespace llvm {
class raw_ostream;
class Triple;
-const unsigned MAX_SUBTARGET_WORDS = 4;
+const unsigned MAX_SUBTARGET_WORDS = 5;
const unsigned MAX_SUBTARGET_FEATURES = MAX_SUBTARGET_WORDS * 64;
/// Container class for subtarget features.
diff --git a/llvm/lib/Target/AArch64/AArch64.td b/llvm/lib/Target/AArch64/AArch64.td
index 8fd9358c9f9c7a0..d53abfd29b1edcb 100644
--- a/llvm/lib/Target/AArch64/AArch64.td
+++ b/llvm/lib/Target/AArch64/AArch64.td
@@ -517,6 +517,12 @@ def FeatureSME2p1 : SubtargetFeature<"sme2p1", "HasSME2p1", "true",
def FeatureFAMINMAX: SubtargetFeature<"faminmax", "HasFAMINMAX", "true",
"Enable FAMIN and FAMAX instructions (FEAT_FAMINMAX)">;
+def FeatureLUT: SubtargetFeature<"lut", "HasLUT", "true",
+ "Enable Lookup Table instructions (FEAT_LUT)">;
+
+def FeatureSME_LUTv2 : SubtargetFeature<"sme-lutv2", "HasSME_LUTv2", "true",
+ "Enable Scalable Matrix Extension (SME) LUTv2 instructions (FEAT_SME_LUTv2)", [FeatureSME2, FeatureFP8]>;
+
def FeatureAppleA7SysReg : SubtargetFeature<"apple-a7-sysreg", "HasAppleA7SysReg", "true",
"Apple A7 (the CPU formerly known as Cyclone)">;
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index a48bf77a774b75c..580275f72e40509 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -8095,6 +8095,54 @@ multiclass SIMDTableLookupTied<bit op, string asm> {
V128, VecListFour128>;
}
+//----------------------------------------------------------------------------
+// AdvSIMD LUT
+//----------------------------------------------------------------------------
+let mayLoad = 0, mayStore = 0, hasSideEffects = 0 in
+class BaseSIMDTableLookupIndexed<bit Q, bits<5> opc, RegisterOperand vectype,
+ RegisterOperand listtype, Operand idx_type,
+ string asm, string kind>
+ : I<(outs vectype:$Rd),
+ (ins listtype:$Rn, vectype:$Rm, idx_type:$idx),
+ asm, "\t$Rd" # kind # ", $Rn, $Rm$idx", "", []>,
+ Sched<[]> {
+ bits<5> Rd;
+ bits<5> Rn;
+ bits<5> Rm;
+ let Inst{31} = 0;
+ let Inst{30} = Q;
+ let Inst{29-24} = 0b001110;
+ let Inst{23-22} = opc{4-3};
+ let Inst{21} = 0;
+ let Inst{20-16} = Rm;
+ let Inst{15} = 0;
+ let Inst{14-12} = opc{2-0};
+ let Inst{11-10} = 0b00;
+ let Inst{9-5} = Rn;
+ let Inst{4-0} = Rd;
+}
+
+multiclass BaseSIMDTableLookupIndexed2<string asm> {
+ def v16f8 : BaseSIMDTableLookupIndexed<0b1, {0b10,?,?,0b1}, V128, VecListOne16b, VectorIndexS, asm, ".16b"> {
+ bits<2> idx;
+ let Inst{14-13} = idx;
+ }
+ def v8f16 : BaseSIMDTableLookupIndexed<0b1, {0b11,?,?,?}, V128, VecListOne8h, VectorIndexH, asm, ".8h" > {
+ bits<3> idx;
+ let Inst{14-12} = idx;
+ }
+}
+
+multiclass BaseSIMDTableLookupIndexed4<string asm> {
+ def v16f8 : BaseSIMDTableLookupIndexed<0b1, {0b01,?,0b10}, V128, VecListOne16b, VectorIndexD, asm, ".16b"> {
+ bit idx;
+ let Inst{14} = idx;
+ }
+ def v8f16 : BaseSIMDTableLookupIndexed<0b1, {0b01,?,?,0b1}, V128, VecListTwo8h, VectorIndexS, asm, ".8h" > {
+ bits<2> idx;
+ let Inst{14-13} = idx;
+ }
+}
//----------------------------------------------------------------------------
// AdvSIMD scalar DUP
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 069a283dd311e50..ec972ce71cb1047 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -166,6 +166,10 @@ def HasFP8 : Predicate<"Subtarget->hasFP8()">,
AssemblerPredicateWithAll<(all_of FeatureFP8), "fp8">;
def HasFAMINMAX : Predicate<"Subtarget->hasFAMINMAX()">,
AssemblerPredicateWithAll<(all_of FeatureFAMINMAX), "faminmax">;
+def HasLUT : Predicate<"Subtarget->hasLUT()">,
+ AssemblerPredicateWithAll<(all_of FeatureLUT), "lut">;
+def HasSME_LUTv2 : Predicate<"Subtarget->hasSME_LUTv2()">,
+ AssemblerPredicateWithAll<(all_of FeatureSME_LUTv2), "sme-lutv2">;
// A subset of SVE(2) instructions are legal in Streaming SVE execution mode,
// they should be enabled if either has been specified.
@@ -5940,6 +5944,13 @@ def : Pat<(v16i8 (int_aarch64_neon_tbx1 (v16i8 V128:$Rd),
(v16i8 V128:$Ri), (v16i8 V128:$Rn))),
(TBXv16i8One V128:$Rd, V128:$Ri, V128:$Rn)>;
+//----------------------------------------------------------------------------
+// AdvSIMD LUT instructions
+//----------------------------------------------------------------------------
+let Predicates = [HasLUT] in {
+ defm LUT2 : BaseSIMDTableLookupIndexed2<"luti2">;
+ defm LUT4 : BaseSIMDTableLookupIndexed4<"luti4">;
+}
//----------------------------------------------------------------------------
// AdvSIMD scalar DUP instruction
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
index eb26591908fd79c..57ad51641a2f41e 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
@@ -1252,6 +1252,10 @@ class ZPRVectorListMul<int ElementWidth, int NumRegs> : ZPRVectorList<ElementWid
let EncoderMethod = "EncodeRegAsMultipleOf<2>",
DecoderMethod = "DecodeZPR2Mul2RegisterClass" in {
+ def ZZ_mul_r : RegisterOperand<ZPR2Mul2, "printTypedVectorList<0,0>"> {
+ let ParserMatchClass = ZPRVectorListMul<0, 2>;
+ }
+
def ZZ_b_mul_r : RegisterOperand<ZPR2Mul2, "printTypedVectorList<0,'b'>"> {
let ParserMatchClass = ZPRVectorListMul<8, 2>;
}
diff --git a/llvm/lib/Target/AArch64/AArch64SMEInstrInfo.td b/llvm/lib/Target/AArch64/AArch64SMEInstrInfo.td
index f55b84b02f85162..7f568c9a225952e 100644
--- a/llvm/lib/Target/AArch64/AArch64SMEInstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64SMEInstrInfo.td
@@ -885,3 +885,12 @@ defm FAMIN_2Z2Z : sme2_fp_sve_destructive_vector_vg2_multi<"famin", 0b0010101>;
defm FAMAX_4Z4Z : sme2_fp_sve_destructive_vector_vg4_multi<"famax", 0b0010100>;
defm FAMIN_4Z4Z : sme2_fp_sve_destructive_vector_vg4_multi<"famin", 0b0010101>;
} //[HasSME2, HasFAMINMAX]
+
+let Predicates = [HasSME2, HasSME_LUTv2] in {
+defm MOVT : sme2_movt_zt_to_zt<"movt", 0b0011111>;
+def LUTI4_4ZZT2Z : sme2_luti4_vector_vg4<0b00, 0b00,"luti4">;
+} //[HasSME2, HasSME_LUTv2]
+
+let Predicates = [HasSME2p1, HasSME_LUTv2] in {
+def LUTI4_S_4ZZT2Z : sme2_luti4_vector_vg4_strided<0b00, 0b00, "luti4">;
+} //[HasSME2p1, HasSME_LUTv2]
diff --git a/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td b/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td
index 1a586765d58b3ca..f192cd7dbcc5135 100644
--- a/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td
@@ -4029,3 +4029,12 @@ let Predicates = [HasSVE2orSME2, HasFAMINMAX] in {
defm FAMIN_ZPmZ : sve_fp_2op_p_zds<0b1111, "famin", "", null_frag, DestructiveOther>;
defm FAMAX_ZPmZ : sve_fp_2op_p_zds<0b1110, "famax", "", null_frag, DestructiveOther>;
} // End HasSVE2orSME2, HasFAMINMAX
+
+let Predicates = [HasSVE2orSME2, HasLUT] in {
+// LUTI2
+ defm LUTI2_ZZZI : sve2_luti2_vector_index<"luti2">;
+// LUTI4
+ defm LUTI4_ZZZI : sve2_luti4_vector_index<"luti4">;
+// LUTI4 (two contiguous registers)
+ defm LUTI4_Z2ZZI : sve2_luti4_vector_vg2_index<"luti4">;
+} // End HasSVE2orSME2, HasLUT
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 35abe3563eb81ab..874e46237f3707e 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -3641,6 +3641,8 @@ static const struct Extension {
{"fpmr", {AArch64::FeatureFPMR}},
{"fp8", {AArch64::FeatureFP8}},
{"faminmax", {AArch64::FeatureFAMINMAX}},
+ {"lut", {AArch64::FeatureLUT}},
+ {"sme-lutv2", {AArch64::FeatureSME_LUTv2}},
};
static void setRequiredFeatureString(FeatureBitset FBS, std::string &Str) {
@@ -4536,7 +4538,7 @@ ParseStatus AArch64AsmParser::tryParseZTOperand(OperandVector &Operands) {
Operands.push_back(AArch64Operand::CreateReg(
RegNum, RegKind::LookupTable, StartLoc, getLoc(), getContext()));
- Lex(); // Eat identifier token.
+ Lex(); // Eat register.
// Check if register is followed by an index
if (parseOptionalToken(AsmToken::LBrac)) {
@@ -4546,14 +4548,18 @@ ParseStatus AArch64AsmParser::tryParseZTOperand(OperandVector &Operands) {
if (getParser().parseExpression(ImmVal))
return ParseStatus::NoMatch;
const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(ImmVal);
+ Operands.push_back(AArch64Operand::CreateImm(
+ MCConstantExpr::create(MCE->getValue(), getContext()), StartLoc,
+ getLoc(), getContext()));
if (!MCE)
return TokError("immediate value expected for vector index");
+ if (getTok().is(AsmToken::Comma)) {
+ Lex(); // eat comma
+ if (parseOptionalMulOperand(Operands))
+ return MatchOperand_ParseFail;
+ }
if (parseToken(AsmToken::RBrac, "']' expected"))
return ParseStatus::Failure;
-
- Operands.push_back(AArch64Operand::CreateImm(
- MCConstantExpr::create(MCE->getValue(), getContext()), StartLoc,
- getLoc(), getContext()));
Operands.push_back(
AArch64Operand::CreateToken("]", getLoc(), getContext()));
}
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
index 988c78699179f0c..c5de5b4de4aef3a 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
@@ -1740,6 +1740,10 @@ template <unsigned NumLanes, char LaneKind>
void AArch64InstPrinter::printTypedVectorList(const MCInst *MI, unsigned OpNum,
const MCSubtargetInfo &STI,
raw_ostream &O) {
+ if (LaneKind == 0) {
+ printVectorList(MI, OpNum, STI, O, "");
+ return;
+ }
std::string Suffix(".");
if (NumLanes)
Suffix += itostr(NumLanes) + LaneKind;
diff --git a/llvm/lib/Target/AArch64/SMEInstrFormats.td b/llvm/lib/Target/AArch64/SMEInstrFormats.td
index d8b44c68fbdee10..c94ec8004d0c570 100644
--- a/llvm/lib/Target/AArch64/SMEInstrFormats.td
+++ b/llvm/lib/Target/AArch64/SMEInstrFormats.td
@@ -3059,6 +3059,25 @@ class sme2_movt_scalar_to_zt<string mnemonic, bits<7> opc>
let Inst{4-0} = Rt;
}
+// SME2 move vector to lookup table
+class sme2_movt_zt_to_zt<string mnemonic, bits<7> opc>
+ : I<(outs ZTR:$ZTt), (ins sme_elm_idx0_3:$off2, ZPRAny:$Zt),
+ mnemonic, "\t$ZTt[$off2, mul vl], $Zt",
+ "", []>, Sched<[]> {
+ bits<5> Zt;
+ bits<2> off2;
+ let Inst{31-14} = 0b110000000100111100;
+ let Inst{13-12} = off2;
+ let Inst{11-5} = opc;
+ let Inst{4-0} = Zt;
+}
+
+multiclass sme2_movt_zt_to_zt<string mnemonic, bits<7> opc> {
+ def NAME : sme2_movt_zt_to_zt<mnemonic, opc>;
+ def : InstAlias<mnemonic # "\t$ZTt, $Zt",
+ (!cast<Instruction>(NAME) ZTR:$ZTt, 0, ZPRAny:$Zt), 1>;
+}
+
//===----------------------------------------------------------------------===//
// SME2 lookup table expand one register
class sme2_luti_vector_index<bits<2> sz, bits<7> opc, RegisterOperand vector_ty,
@@ -4713,3 +4732,36 @@ class sme2p1_luti4_vector_vg4_index<bits<2> sz, RegisterOperand vector_ty,
multiclass sme2p1_luti4_vector_vg4_index<string mnemonic> {
def _H: sme2p1_luti4_vector_vg4_index<0b01, ZZZZ_h_strided, VectorIndexD, mnemonic>;
}
+
+// SME2 lookup table two source registers expand to four contiguous destination registers
+class sme2_luti4_vector_vg4<bits<2> sz, bits<2> op, string mnemonic>
+ : I<(outs ZZZZ_b_mul_r:$Zd), (ins ZTR:$ZTt, ZZ_mul_r:$Zn),
+ mnemonic, "\t$Zd, $ZTt, $Zn",
+ "", []>, Sched<[]> {
+ bits<4> Zn;
+ bits<3> Zd;
+ let Inst{31-14} = 0b110000001000101100;
+ let Inst{13-12} = sz;
+ let Inst{11-10} = op;
+ let Inst{9-6} = Zn;
+ let Inst{5} = 0b0;
+ let Inst{4-2} = Zd;
+ let Inst{1-0} = 0b00;
+}
+
+// SME2 lookup table two source registers expand to four non-contiguous destination registers
+class sme2_luti4_vector_vg4_strided<bits<2> sz, bits<2> op, string mnemonic>
+ : I<(outs ZZZZ_b_strided:$Zd), (ins ZTR:$ZTt, ZZ_mul_r:$Zn),
+ mnemonic, "\t$Zd, $ZTt, $Zn",
+ "", []>, Sched<[]> {
+ bits<4> Zn;
+ bits<3> Zd;
+ let Inst{31-14} = 0b110000001001101100;
+ let Inst{13-12} = sz;
+ let Inst{11-10} = op;
+ let Inst{9-6} = Zn;
+ let Inst{5} = 0b0;
+ let Inst{4} = Zd{2};
+ let Inst{3-2} = 0b00;
+ let Inst{1-0} = Zd{1-0};
+}
diff --git a/llvm/lib/Target/AArch64/SVEInstrFormats.td b/llvm/lib/Target/AArch64/SVEInstrFormats.td
index d2f72fda3a229b8..5c6c83b267fe46d 100644
--- a/llvm/lib/Target/AArch64/SVEInstrFormats.td
+++ b/llvm/lib/Target/AArch64/SVEInstrFormats.td
@@ -10120,4 +10120,56 @@ class sve2_fp8_down_cvt_single<bits<2> opc, string mnemonic,
multiclass sve2_fp8_down_cvt_single<bits<2> opc, string mnemonic, RegisterOperand src> {
def NAME : sve2_fp8_down_cvt_single<opc, mnemonic, ZPR8, src>;
+}
+
+// FP8 Look up table
+class sve2_lut_vector_index<ZPRRegOp zd_ty, RegisterOperand zn_ty,
+ Operand idx_ty, bits<4>opc, string mnemonic>
+ : I<(outs zd_ty:$Zd), (ins zn_ty:$Zn, ZPRAny:$Zm, idx_ty:$idx),
+ mnemonic, "\t$Zd, $Zn, $Zm$idx",
+ "", []>, Sched<[]> {
+ bits<5> Zd;
+ bits<5> Zn;
+ bits<5> Zm;
+ let Inst{31-24} = 0b01000101;
+ let Inst{22} = opc{3};
+ let Inst{21} = 0b1;
+ let Inst{20-16} = Zm;
+ let Inst{15-13} = 0b101;
+ let Inst{12-10} = opc{2-0};
+ let Inst{9-5} = Zn;
+ let Inst{4-0} = Zd;
+}
+
+// FP8 Look up table read with 2-bit indices
+multiclass sve2_luti2_vector_index<string mnemonic> {
+ def _B : sve2_lut_vector_index<ZPR8, Z_b, VectorIndexS32b, {?, 0b100}, mnemonic> {
+ bits<2> idx;
+ let Inst{23-22} = idx;
+ }
+ def _H : sve2_lut_vector_index<ZPR16, Z_h, VectorIndexH32b, {?,?,0b10}, mnemonic> {
+ bits<3> idx;
+ let Inst{23-22} = idx{2-1};
+ let Inst{12} = idx{0};
+ }
+}
+
+// FP8 Look up table read with 4-bit indices
+multiclass sve2_luti4_vector_index<string mnemonic> {
+ def _B : sve2_lut_vector_index<ZPR8, Z_b, VectorIndexD32b, 0b1001, mnemonic> {
+ bit idx;
+ let Inst{23} = idx;
+ }
+ def _H : sve2_lut_vector_index<ZPR16, Z_h, VectorIndexS32b, {?, 0b111}, mnemonic> {
+ bits<2> idx;
+ let Inst{23-22} = idx;
+ }
+}
+
+// FP8 Look up table read with 4-bit indices (two contiguous registers)
+multiclass sve2_luti4_vector_vg2_index<string mnemonic> {
+ def _H : sve2_lut_vector_index<ZPR16, ZZ_h, VectorIndexS32b, {?, 0b101}, mnemonic> {
+ bits<2> idx;
+ let Inst{23-22} = idx;
+ }
}
\ No newline at end of file
diff --git a/llvm/test/MC/AArch64/FP8/directive-arch-negative.s b/llvm/test/MC/AArch64/FP8/directive-arch-negative.s
index 86525ff68134c91..33cd713634f1bc5 100644
--- a/llvm/test/MC/AArch64/FP8/directive-arch-negative.s
+++ b/llvm/test/MC/AArch64/FP8/directive-arch-negative.s
@@ -12,3 +12,20 @@ famax v31.4h, v31.4h, v31.4h
// CHECK: error: instruction requires: faminmax
// CHECK: famax v31.4h, v31.4h, v31.4h
+.arch armv9-a+lut
+.arch armv9-a+nolut
+luti2 v30.8h, { v20.8h }, v31[7]
+// CHECK: error: instruction requires: lut
+// CHECK: luti2 v30.8h, { v20.8h }, v31[7]
+
+.arch armv9-a+sve2+lut
+.arch armv9-a+nosve2+nolut
+luti2 z0.h, { z0.h }, z0[0]
+// CHECK: error: instruction requires: lut sve2 or sme2
+// CHECK: luti2 z0.h, { z0.h }, z0[0]
+
+.arch armv9-a+sme-lutv2
+.arch armv9-a+nosme-lutv2
+luti4 { z0.b - z3.b }, zt0, { z0, z1 }
+// CHECK: error: instruction requires: sme2 sme-lutv2
+// CHECK: luti4 { z0.b - z3.b }, zt0, { z0, z1 }
diff --git a/llvm/test/MC/AArch64/FP8/directive-arch.s b/llvm/test/MC/AArch64/FP8/directive-arch.s
index e3f0a94c2ff9a37..b1d2aa9b0b7230b 100644
--- a/llvm/test/MC/AArch64/FP8/directive-arch.s
+++ b/llvm/test/MC/AArch64/FP8/directive-arch.s
@@ -3,11 +3,24 @@
.arch armv9-a+fp8
bf1cvtl v0.8h, v0.8b
// CHECK: bf1cvtl v0.8h, v0.8b
-
.arch armv9-a+nofp8
+
.arch armv9-a+faminmax
famax v31.4h, v31.4h, v31.4h
// CHECK: famax v31.4h, v31.4h, v31.4h
-
.arch armv9-a+nofaminmax
+.arch armv9-a+lut
+luti2 v30.8h, {v20.8h}, v31[7]
+// CHECK: luti2 v30.8h, { v20.8h }, v31[7]
+.arch armv9-a+nolut
+
+.arch armv9-a+sve2+lut
+luti2 z0.h, {z0.h}, z0[0]
+// CHECK: luti2 z0.h, { z0.h }, z0[0]
+.arch armv9-a+nosve2+nolut
+
+.arch armv9-a+sme-lutv2
+luti4 {z0.b-z3.b}, zt0, {z0-z1}
+// CHECK: luti4 { z0.b - z3.b }, zt0, { z0, z1 }
+.arch armv9-a+nosme-lutv2
diff --git a/llvm/test/MC/AArch64/FP8/luti2-diagnostics.s b/llvm/test/MC/AArch64/FP8/luti2-diagnostics.s
new file mode 100644
index 000000000000000..1f32fd8b0c027ed
--- /dev/null
+++ b/llvm/test/MC/AArch64/FP8/luti2-diagnostics.s
@@ -0,0 +1,37 @@
+// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+lut 2>&1 < %s| FileCheck %s
+
+// --------------------------------------------------------------------------//
+// Invalid lane indices
+
+luti2 v2.16b, {v1.16b}, v0[-1]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 3].
+// CHECK-NEXT: luti2 v2.16b, {v1.16b}, v0[-1]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+luti2 v3.16b, {v2.16b}, v1[4]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 3].
+// CHECK-NEXT: luti2 v3.16b, {v2.16b}, v1[4]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+luti2 v30.8h, {v21.8h}, v20[-1]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 7].
+// CHECK-NEXT: luti2 v30.8h, {v21.8h}, v20[-1]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+luti2 v31.8h, {v31.8h}, v31[8]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 7].
+// CHECK-NEXT: luti2 v31.8h, {v31.8h}, v31[8]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+// --------------------------------------------------------------------------//
+// Invalid vector suffix
+
+luti2 v2.8h, {v1.16b}, v0[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: luti2 v2.8h, {v1.16b}, v0[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+luti2 v31.16b, {v31.8h}, v31[7]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: luti2 v31.16b, {v31.8h}, v31[7]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
diff --git a/llvm/test/MC/AArch64/FP8/luti2.s b/llvm/test/MC/AArch64/FP8/luti2.s
new file mode 100644
index 000000000000000..c5f99f0fb87cb15
--- /dev/null
+++ b/llvm/test/MC/AArch64/FP8/luti2.s
@@ -0,0 +1,41 @@
+// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+lut < %s \
+// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST
+
+// RUN: not llvm-mc -triple=aarch64 -show-encoding < %s 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-ERROR
+
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+lut < %s \
+// RUN: | llvm-objdump -d --mattr=+lut - | FileCheck %s --check-prefix=CHECK-INST
+
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+lut < %s \
+// RUN: | llvm-objdump -d --mattr=-lut - | FileCheck %s --check-prefix=CHECK-UNKNOWN
+
+// Disassemble encoding and check the re-encoding (-show-encoding) matches.
+// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+lut < %s \
+// RUN: | sed '/.text/d' | sed 's/.*encoding: //g' \
+// RUN: | llvm-mc -triple=aarch64 -mattr=+lut -disassemble -show-encoding \
+// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST
+
+luti2 v1.16b, {v2.16b}, v0[0] // 01001110-10000000-00010000-01000001
+// CHECK-INST: luti2 v1.16b, { v2.16b }, v0[0]
+// CHECK-ENCODING: [0x41,0x10,0x80,0x4e]
+// CHECK-ERROR: instruction requires: lut
+// CHECK-UNKNOWN: 4e801041 <unknown>
+
+luti2 v30.16b, {v20.16b}, v31[3] // 01001110-10011111-01110010-10011110
+// CHECK-INST: luti2 v30.16b, { v20.16b }, v31[3]
+// CHECK-ENCODING: [0x9e,0x72,0x9f,0x4e]
+// CHECK-ERROR: instruction requires: lut
+// CHECK-UNKNOWN: 4e9f729e <unknown>
+
+luti2 v1.8h, {v2.8h}, v0[0] // 01001110-11000000-00000000-01000001
+// CHECK-INST: luti2 v1.8h, { v2.8h }, v0[0]
+// CHECK-ENCODING: [0x41,0x00,0xc0,0x4e]
+// CHECK-ERROR: instruction requires: lut
+// CHECK-UNKNOWN: 4ec00041 <unknown>
+
+luti2 v30.8h, {v20.8h}, v31[7] // 01001110-11011111-01110010-10011110
+// CHECK-INST: luti2 v30.8h, { v20.8h }, v31[7]
+// CHECK-ENCODING: [0x9e,0x72,0xdf,0x4e]
+// CHECK-ERROR: instruction requires: lut
+// CHECK-UNKNOWN: 4edf729e <unknown>
diff --git a/llvm/test/MC/AArch64/FP8/luti4-diagnostics.s b/llvm/test/MC/AArch64/FP8/luti4-diagnostics.s
new file mode 100644
index 000000000000000..a8b936d87c2fa7b
--- /dev/null
+++ b/llvm/test/MC/AArch64/FP8/luti4-diagnostics.s
@@ -0,0 +1,50 @@
+// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+lut 2>&1 < %s| FileCheck %s
+
+// --------------------------------------------------------------------------//
+// Invalid lane indices
+
+luti4 v2.16b, {v1.16b}, v0[-1]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 1].
+// CHECK-NEXT: luti4 v2.16b, {v1.16b}, v0[-1]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+luti4 v3.16b, {v2.16b}, v1[2]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 1].
+// CHECK-NEXT: luti4 v3.16b, {v2.16b}, v1[2]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+luti4 v3.8h, {v0.8h, v1.8h}, v2[-1]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 3].
+// CHECK-NEXT: luti4 v3.8h, {v0.8h, v1.8h}, v2[-1]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+luti4 v3.8h, {v0.8h, v1.8h}, v2[4]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 3].
+// CHECK-NEXT: luti4 v3.8h, {v0.8h, v1.8h}, v2[4]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+// --------------------------------------------------------------------------//
+// Invalid vector lists
+
+luti4 v30.8h, {v0.8h, v2.8h}, v3[2]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: luti4 v30.8h, {v0.8h, v2.8h}, v3[2]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+// --------------------------------------------------------------------------//
+// Invalid vector suffix
+
+luti4 v2.8h, {v1.16b}, v0[1]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: luti4 v2.8h, {v1.16b}, v0[1]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+luti4 v31.8h, {v20.16b, v21.16b}, v31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: luti4 v31.8h, {v20.16b, v21.16b}, v31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+luti4 v3.s, {v0.8h, v1.8h}, v2[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: luti4 v3.s, {v0.8h, v1.8h}, v2[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
\ No newline at end of file
diff --git a/llvm/test/MC/AArch64/FP8/luti4.s b/llvm/test/MC/AArch64/FP8/luti4.s
new file mode 100644
index 000000000000000..77e5b708f619cd3
--- /dev/null
+++ b/llvm/test/MC/AArch64/FP8/luti4.s
@@ -0,0 +1,41 @@
+// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+lut < %s \
+// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST
+
+// RUN: not llvm-mc -triple=aarch64 -show-encoding < %s 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-ERROR
+
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+lut < %s \
+// RUN: | llvm-objdump -d --mattr=+lut - | FileCheck %s --check-prefix=CHECK-INST
+
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+lut < %s \
+// RUN: | llvm-objdump -d --mattr=-lut - | FileCheck %s --check-prefix=CHECK-UNKNOWN
+
+// Disassemble encoding and check the re-encoding (-show-encoding) matches.
+// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+lut < %s \
+// RUN: | sed '/.text/d' | sed 's/.*encoding: //g' \
+// RUN: | llvm-mc -triple=aarch64 -mattr=+lut -disassemble -show-encoding \
+// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST
+
+luti4 v1.16b, {v2.16b}, v0[0] // 01001110-01000000-00100000-01000001
+// CHECK-INST: luti4 v1.16b, { v2.16b }, v0[0]
+// CHECK-ENCODING: [0x41,0x20,0x40,0x4e]
+// CHECK-ERROR: instruction requires: lut
+// CHECK-UNKNOWN: 4e402041 <unknown>
+
+luti4 v30.16b, {v20.16b}, v31[1] // 01001110-01011111-01100010-10011110
+// CHECK-INST: luti4 v30.16b, { v20.16b }, v31[1]
+// CHECK-ENCODING: [0x9e,0x62,0x5f,0x4e]
+// CHECK-ERROR: instruction requires: lut
+// CHECK-UNKNOWN: 4e5f629e <unknown>
+
+luti4 v1.8h, {v2.8h, v3.8h}, v0[0] // 01001110-01000000-00010000-01000001
+// CHECK-INST: luti4 v1.8h, { v2.8h, v3.8h }, v0[0]
+// CHECK-ENCODING: [0x41,0x10,0x40,0x4e]
+// CHECK-ERROR: instruction requires: lut
+// CHECK-UNKNOWN: 4e401041 <unknown>
+
+luti4 v30.8h, {v20.8h, v21.8h}, v31[3] // 01001110-01011111-01110010-10011110
+// CHECK-INST: luti4 v30.8h, { v20.8h, v21.8h }, v31[3]
+// CHECK-ENCODING: [0x9e,0x72,0x5f,0x4e]
+// CHECK-ERROR: instruction requires: lut
+// CHECK-UNKNOWN: 4e5f729e <unknown>
diff --git a/llvm/test/MC/AArch64/FP8_SME2/lut-diagnostics.s b/llvm/test/MC/AArch64/FP8_SME2/lut-diagnostics.s
new file mode 100644
index 000000000000000..36a5b12bc482317
--- /dev/null
+++ b/llvm/test/MC/AArch64/FP8_SME2/lut-diagnostics.s
@@ -0,0 +1,27 @@
+// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+sme2p1,+sme-lutv2 2>&1 < %s | FileCheck %s
+
+// --------------------------------------------------------------------------//
+// Invalid vector select register
+
+luti4 {z0-z3}, zt0, {z0.b-z1.b}
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: luti4 {z0-z3}, zt0, {z0.b-z1.b}
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+luti4 {z0.d, z4.d, z8.d, z12.d}, zt0, {z0-z1}
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: luti4 {z0.d, z4.d, z8.d, z12.d}, zt0, {z0-z1}
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+// --------------------------------------------------------------------------//
+// Invalid vector grouping
+
+luti4 {z0.b-z1.b}, zt0, {z0-z4}
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid number of vectors
+// CHECK-NEXT: luti4 {z0.b-z1.b}, zt0, {z0-z4}
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+luti4 {z0.b - z12.b}, zt0, {z0-z1}
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid number of vectors
+// CHECK-NEXT: luti4 {z0.b - z12.b}, zt0, {z0-z1}
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
diff --git a/llvm/test/MC/AArch64/FP8_SME2/lut.s b/llvm/test/MC/AArch64/FP8_SME2/lut.s
new file mode 100644
index 000000000000000..968eb8dd23444d9
--- /dev/null
+++ b/llvm/test/MC/AArch64/FP8_SME2/lut.s
@@ -0,0 +1,35 @@
+// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sme2,+sme2p1,+sme-lutv2 < %s \
+// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST
+// RUN: not llvm-mc -triple=aarch64 -show-encoding < %s 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-ERROR
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sme2,+sme2p1,+sme-lutv2 < %s \
+// RUN: | llvm-objdump -d --mattr=+sme2,+sme2p1,+sme-lutv2 --no-print-imm-hex - \
+// RUN: | FileCheck %s --check-prefix=CHECK-INST
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sme2,+sme2p1,+sme-lutv2 < %s \
+// RUN: | llvm-objdump -d --mattr=-sme-lutv2 --no-print-imm-hex - \
+// RUN: | FileCheck %s --check-prefix=CHECK-UNKNOWN
+
+luti4 {z0.b-z3.b}, zt0, {z0-z1} // 11000000-10001011-00000000-00000000
+// CHECK-INST: luti4 { z0.b - z3.b }, zt0, { z0, z1 }
+// CHECK-ENCODING: [0x00,0x00,0x8b,0xc0]
+// CHECK-ERROR: instruction requires: sme2 sme-lutv2
+// CHECK-UNKNOWN: c08b0000 <unknown>
+
+luti4 {z28.b-z31.b}, zt0, {z30-z31} // 11000000-10001011-00000011-11011100
+// CHECK-INST: luti4 { z28.b - z31.b }, zt0, { z30, z31 }
+// CHECK-ENCODING: [0xdc,0x03,0x8b,0xc0]
+// CHECK-ERROR: instruction requires: sme2 sme-lutv2
+// CHECK-UNKNOWN: c08b03dc <unknown>
+
+// Strided
+luti4 {z0.b, z4.b, z8.b, z12.b}, zt0, {z0-z1} // 11000000-10011011-00000000-00000000
+// CHECK-INST: luti4 { z0.b, z4.b, z8.b, z12.b }, zt0, { z0, z1 }
+// CHECK-ENCODING: [0x00,0x00,0x9b,0xc0]
+// CHECK-ERROR: instruction requires: sme2p1 sme-lutv2
+// CHECK-UNKNOWN: c09b0000 <unknown>
+
+luti4 {z19.b, z23.b, z27.b, z31.b}, zt0, {z30-z31} // 11000000-10011011-00000011-11010011
+// CHECK-INST: luti4 { z19.b, z23.b, z27.b, z31.b }, zt0, { z30, z31 }
+// CHECK-ENCODING: [0xd3,0x03,0x9b,0xc0]
+// CHECK-ERROR: instruction requires: sme2p1 sme-lutv2
+// CHECK-UNKNOWN: c09b03d3 <unknown>
diff --git a/llvm/test/MC/AArch64/FP8_SME2/movt-diagnostics.s b/llvm/test/MC/AArch64/FP8_SME2/movt-diagnostics.s
new file mode 100644
index 000000000000000..ba4538921121565
--- /dev/null
+++ b/llvm/test/MC/AArch64/FP8_SME2/movt-diagnostics.s
@@ -0,0 +1,29 @@
+
+// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+sme2,+sme-lutv2 2>&1 < %s | FileCheck %s
+// --------------------------------------------------------------------------//
+// Invalid vector select register
+movt z0, z31
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: Invalid lookup table, expected zt0
+// CHECK-NEXT: movt z0, z31
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+// --------------------------------------------------------------------------//
+// Invalid vector select offset
+//
+movt zt0[-1, mul vl], z31
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: immediate must be an integer in range [0, 3].
+// CHECK-NEXT: movt zt0[-1, mul vl], z31
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+movt zt0[4, mul vl], z31
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: immediate must be an integer in range [0, 3].
+// CHECK-NEXT: movt zt0[4, mul vl], z31
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+// --------------------------------------------------------------------------//
+// Invalid mul vl
+movt zt0[0, mul vl 3], z0
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: ']' expected
+// CHECK-NEXT: movt zt0[0, mul vl 3], z0
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+movt zt0[0, mul #4], z0
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: movt zt0[0, mul #4], z0
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
diff --git a/llvm/test/MC/AArch64/FP8_SME2/movt.s b/llvm/test/MC/AArch64/FP8_SME2/movt.s
new file mode 100644
index 000000000000000..bcf942cef03c89a
--- /dev/null
+++ b/llvm/test/MC/AArch64/FP8_SME2/movt.s
@@ -0,0 +1,22 @@
+// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sme2,+sme-lutv2 < %s \
+// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST
+// RUN: not llvm-mc -triple=aarch64 -show-encoding < %s 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-ERROR
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sme2,+sme-lutv2 < %s \
+// RUN: | llvm-objdump -d --mattr=+sme2,+sme-lutv2 --no-print-imm-hex - \
+// RUN: | FileCheck %s --check-prefix=CHECK-INST
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sme2,+sme-lutv2 < %s \
+// RUN: | llvm-objdump -d --mattr=-sme-lutv2 --no-print-imm-hex - \
+// RUN: | FileCheck %s --check-prefix=CHECK-UNKNOWN
+
+movt zt0, z0 // 11000000-01001111-00000011-11100000
+// CHECK-INST: movt zt0, z0
+// CHECK-ENCODING: [0xe0,0x03,0x4f,0xc0]
+// CHECK-ERROR: instruction requires: sme2 sme-lutv2
+// CHECK-UNKNOWN: c04f03e0 <unknown>
+
+movt zt0[3, mul vl], z31 // 11000000-01001111-00110011-11111111
+// CHECK-INST: movt zt0[3, mul vl], z31
+// CHECK-ENCODING: [0xff,0x33,0x4f,0xc0]
+// CHECK-ERROR: instruction requires: sme2 sme-lutv2
+// CHECK-UNKNOWN: c04f33ff <unknown>
diff --git a/llvm/test/MC/AArch64/FP8_SVE2/luti2-diagnostics.s b/llvm/test/MC/AArch64/FP8_SVE2/luti2-diagnostics.s
new file mode 100644
index 000000000000000..113d4f3946e3437
--- /dev/null
+++ b/llvm/test/MC/AArch64/FP8_SVE2/luti2-diagnostics.s
@@ -0,0 +1,37 @@
+// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+sve2,+lut 2>&1 < %s| FileCheck %s
+
+// --------------------------------------------------------------------------//
+// Invalid lane indices
+
+luti2 z2.b, {z1.b}, z0[-1]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 3].
+// CHECK-NEXT: luti2 z2.b, {z1.b}, z0[-1]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+luti2 z3.b, {z2.b}, z1[4]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 3].
+// CHECK-NEXT: luti2 z3.b, {z2.b}, z1[4]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+luti2 z30.h, {z21.h}, z20[-1]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 7].
+// CHECK-NEXT: luti2 z30.h, {z21.h}, z20[-1]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+luti2 z31.h, {z31.h}, z31[8]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 7].
+// CHECK-NEXT: luti2 z31.h, {z31.h}, z31[8]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+// --------------------------------------------------------------------------//
+// Invalid vector suffix
+
+luti2 z2.h, {z1.b}, z0[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: luti2 z2.h, {z1.b}, z0[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+luti2 z31.b, {z31.h}, z31[7]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid element width
+// CHECK-NEXT: luti2 z31.b, {z31.h}, z31[7]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
diff --git a/llvm/test/MC/AArch64/FP8_SVE2/luti2.s b/llvm/test/MC/AArch64/FP8_SVE2/luti2.s
new file mode 100644
index 000000000000000..86c310c295b5cab
--- /dev/null
+++ b/llvm/test/MC/AArch64/FP8_SVE2/luti2.s
@@ -0,0 +1,54 @@
+// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sve2,+lut < %s \
+// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST
+
+// RUN: not llvm-mc -triple=aarch64 -show-encoding < %s 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-ERROR
+
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sme2,+lut < %s \
+// RUN: | llvm-objdump -d --mattr=+sme2,+lut --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-INST
+
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sve2,+lut < %s \
+// RUN: | llvm-objdump -d --mattr=-lut --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-UNKNOWN
+
+// Disassemble encoding and check the re-encoding (-show-encoding) matches.
+// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sme2,+lut < %s \
+// RUN: | sed '/.text/d' | sed 's/.*encoding: //g' \
+// RUN: | llvm-mc -triple=aarch64 -mattr=+sme2,+lut -disassemble -show-encoding \
+// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST
+
+luti2 z0.b, {z0.b}, z0[0] // 01000101-00100000-10110000-00000000
+// CHECK-INST: luti2 z0.b, { z0.b }, z0[0]
+// CHECK-ENCODING: [0x00,0xb0,0x20,0x45]
+// CHECK-ERROR: instruction requires: lut sve2 or sme2
+// CHECK-UNKNOWN: 4520b000 <unknown>
+
+
+luti2 z21.b, {z10.b}, z21[1] // 01000101-01110101-10110001-01010101
+// CHECK-INST: luti2 z21.b, { z10.b }, z21[1]
+// CHECK-ENCODING: [0x55,0xb1,0x75,0x45]
+// CHECK-ERROR: instruction requires: lut sve2 or sme2
+// CHECK-UNKNOWN: 4575b155 <unknown>
+
+luti2 z31.b, {z31.b}, z31[3] // 01000101-11111111-10110011-11111111
+// CHECK-INST: luti2 z31.b, { z31.b }, z31[3]
+// CHECK-ENCODING: [0xff,0xb3,0xff,0x45]
+// CHECK-ERROR: instruction requires: lut sve2 or sme2
+// CHECK-UNKNOWN: 45ffb3ff <unknown>
+
+luti2 z0.h, {z0.h}, z0[0] // 01000101-00100000-10101000-00000000
+// CHECK-INST: luti2 z0.h, { z0.h }, z0[0]
+// CHECK-ENCODING: [0x00,0xa8,0x20,0x45]
+// CHECK-ERROR: instruction requires: lut sve2 or sme2
+// CHECK-UNKNOWN: 4520a800 <unknown>
+
+luti2 z21.h, {z10.h}, z21[3] // 01000101-01110101-10111001-01010101
+// CHECK-INST: luti2 z21.h, { z10.h }, z21[3]
+// CHECK-ENCODING: [0x55,0xb9,0x75,0x45]
+// CHECK-ERROR: instruction requires: lut sve2 or sme2
+// CHECK-UNKNOWN: 4575b955 <unknown>
+
+luti2 z31.h, {z31.h}, z31[7] // 01000101-11111111-10111011-11111111
+// CHECK-INST: luti2 z31.h, { z31.h }, z31[7]
+// CHECK-ENCODING: [0xff,0xbb,0xff,0x45]
+// CHECK-ERROR: instruction requires: lut sve2 or sme2
+// CHECK-UNKNOWN: 45ffbbff <unknown>
diff --git a/llvm/test/MC/AArch64/FP8_SVE2/luti4-diagnostics.s b/llvm/test/MC/AArch64/FP8_SVE2/luti4-diagnostics.s
new file mode 100644
index 000000000000000..3b44ca00d6789d8
--- /dev/null
+++ b/llvm/test/MC/AArch64/FP8_SVE2/luti4-diagnostics.s
@@ -0,0 +1,60 @@
+// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+sve2,+lut 2>&1 < %s| FileCheck %s
+
+// --------------------------------------------------------------------------//
+// Invalid lane indices
+
+luti4 z2.b, {z1.b}, z0[-1]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 1].
+// CHECK-NEXT: luti4 z2.b, {z1.b}, z0[-1]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+luti4 z3.b, {z2.b}, z1[2]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 1].
+// CHECK-NEXT: luti4 z3.b, {z2.b}, z1[2]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+luti4 z30.h, {z21.h}, z20[-1]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 3].
+// CHECK-NEXT: luti4 z30.h, {z21.h}, z20[-1]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+luti4 z31.h, {z31.h}, z31[4]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 3].
+// CHECK-NEXT: luti4 z31.h, {z31.h}, z31[4]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+luti4 z3.h, {z0.h, z1.h}, z2[-1]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 3].
+// CHECK-NEXT: luti4 z3.h, {z0.h, z1.h}, z2[-1]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+luti4 z3.h, {z0.h, z1.h}, z2[4]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 3].
+// CHECK-NEXT: luti4 z3.h, {z0.h, z1.h}, z2[4]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+// --------------------------------------------------------------------------//
+// Invalid vector lists
+
+luti4 z30.h, {z0.h, z2.h}, z3[2]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: luti4 z30.h, {z0.h, z2.h}, z3[2]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+// --------------------------------------------------------------------------//
+// Invalid vector suffix
+
+luti4 z2.h, {z1.b}, z0[1]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: luti4 z2.h, {z1.b}, z0[1]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+luti4 z31.h, {z31.b}, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: luti4 z31.h, {z31.b}, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+luti4 z3.s, {z0.h, z1.h}, z2[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid element width
+// CHECK-NEXT: luti4 z3.s, {z0.h, z1.h}, z2[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
diff --git a/llvm/test/MC/AArch64/FP8_SVE2/luti4.s b/llvm/test/MC/AArch64/FP8_SVE2/luti4.s
new file mode 100644
index 000000000000000..ce5137054a447ab
--- /dev/null
+++ b/llvm/test/MC/AArch64/FP8_SVE2/luti4.s
@@ -0,0 +1,65 @@
+// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sve2,+lut < %s \
+// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST
+
+// RUN: not llvm-mc -triple=aarch64 -show-encoding < %s 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-ERROR
+
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sme2,+lut < %s \
+// RUN: | llvm-objdump -d --mattr=+sme2,+lut --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-INST
+
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sve2,+lut < %s \
+// RUN: | llvm-objdump -d --mattr=-lut --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-UNKNOWN
+
+// Disassemble encoding and check the re-encoding (-show-encoding) matches.
+// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sme2,+lut < %s \
+// RUN: | sed '/.text/d' | sed 's/.*encoding: //g' \
+// RUN: | llvm-mc -triple=aarch64 -mattr=+sme2,+lut -disassemble -show-encoding \
+// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST
+
+luti4 z0.b, {z0.b}, z0[0] // 01000101-01100000-10100100-00000000
+// CHECK-INST: luti4 z0.b, { z0.b }, z0[0]
+// CHECK-ENCODING: [0x00,0xa4,0x60,0x45]
+// CHECK-ERROR: instruction requires: lut sve2 or sme2
+// CHECK-UNKNOWN: 4560a400 <unknown>
+
+luti4 z31.b, {z31.b}, z31[1] // 01000101-11111111-10100111-11111111
+// CHECK-INST: luti4 z31.b, { z31.b }, z31[1]
+// CHECK-ENCODING: [0xff,0xa7,0xff,0x45]
+// CHECK-ERROR: instruction requires: lut sve2 or sme2
+// CHECK-UNKNOWN: 45ffa7ff <unknown>
+
+luti4 z0.h, {z0.h}, z0[0] // 01000101-00100000-10111100-00000000
+// CHECK-INST: luti4 z0.h, { z0.h }, z0[0]
+// CHECK-ENCODING: [0x00,0xbc,0x20,0x45]
+// CHECK-ERROR: instruction requires: lut sve2 or sme2
+// CHECK-UNKNOWN: 4520bc00 <unknown>
+
+luti4 z21.h, {z10.h}, z21[1] // 01000101-01110101-10111101-01010101
+// CHECK-INST: luti4 z21.h, { z10.h }, z21[1]
+// CHECK-ENCODING: [0x55,0xbd,0x75,0x45]
+// CHECK-ERROR: instruction requires: lut sve2 or sme2
+// CHECK-UNKNOWN: 4575bd55 <unknown>
+
+luti4 z31.h, {z31.h}, z31[3] // 01000101-11111111-10111111-11111111
+// CHECK-INST: luti4 z31.h, { z31.h }, z31[3]
+// CHECK-ENCODING: [0xff,0xbf,0xff,0x45]
+// CHECK-ERROR: instruction requires: lut sve2 or sme2
+// CHECK-UNKNOWN: 45ffbfff <unknown>
+
+luti4 z0.h, {z0.h, z1.h}, z0[0] // 01000101-00100000-10110100-00000000
+// CHECK-INST: luti4 z0.h, { z0.h, z1.h }, z0[0]
+// CHECK-ENCODING: [0x00,0xb4,0x20,0x45]
+// CHECK-ERROR: instruction requires: lut sve2 or sme2
+// CHECK-UNKNOWN: 4520b400 <unknown>
+
+luti4 z21.h, {z10.h, z11.h}, z21[1] // 01000101-01110101-10110101-01010101
+// CHECK-INST: luti4 z21.h, { z10.h, z11.h }, z21[1]
+// CHECK-ENCODING: [0x55,0xb5,0x75,0x45]
+// CHECK-ERROR: instruction requires: lut sve2 or sme2
+// CHECK-UNKNOWN: 4575b555 <unknown>
+
+luti4 z31.h, {z31.h, z0.h}, z31[3] // 01000101-11111111-10110111-11111111
+// CHECK-INST: luti4 z31.h, { z31.h, z0.h }, z31[3]
+// CHECK-ENCODING: [0xff,0xb7,0xff,0x45]
+// CHECK-ERROR: instruction requires: lut sve2 or sme2
+// CHECK-UNKNOWN: 45ffb7ff <unknown>
diff --git a/llvm/unittests/TargetParser/TargetParserTest.cpp b/llvm/unittests/TargetParser/TargetParserTest.cpp
index 45f39a66ea8b343..865a64b75c5d666 100644
--- a/llvm/unittests/TargetParser/TargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/TargetParserTest.cpp
@@ -1713,26 +1713,27 @@ TEST(TargetParserTest, testAArch64Extension) {
TEST(TargetParserTest, AArch64ExtensionFeatures) {
std::vector<uint64_t> Extensions = {
- AArch64::AEK_CRC, AArch64::AEK_LSE, AArch64::AEK_RDM,
- AArch64::AEK_CRYPTO, AArch64::AEK_SM4, AArch64::AEK_SHA3,
- AArch64::AEK_SHA2, AArch64::AEK_AES, AArch64::AEK_DOTPROD,
- AArch64::AEK_FP, AArch64::AEK_SIMD, AArch64::AEK_FP16,
- AArch64::AEK_FP16FML, AArch64::AEK_PROFILE, AArch64::AEK_RAS,
- AArch64::AEK_SVE, AArch64::AEK_SVE2, AArch64::AEK_SVE2AES,
- AArch64::AEK_SVE2SM4, AArch64::AEK_SVE2SHA3, AArch64::AEK_SVE2BITPERM,
- AArch64::AEK_RCPC, AArch64::AEK_RAND, AArch64::AEK_MTE,
- AArch64::AEK_SSBS, AArch64::AEK_SB, AArch64::AEK_PREDRES,
- AArch64::AEK_BF16, AArch64::AEK_I8MM, AArch64::AEK_F32MM,
- AArch64::AEK_F64MM, AArch64::AEK_TME, AArch64::AEK_LS64,
- AArch64::AEK_BRBE, AArch64::AEK_PAUTH, AArch64::AEK_FLAGM,
- AArch64::AEK_SME, AArch64::AEK_SMEF64F64, AArch64::AEK_SMEI16I64,
- AArch64::AEK_SME2, AArch64::AEK_HBC, AArch64::AEK_MOPS,
- AArch64::AEK_PERFMON, AArch64::AEK_SVE2p1, AArch64::AEK_SME2p1,
- AArch64::AEK_B16B16, AArch64::AEK_SMEF16F16, AArch64::AEK_CSSC,
- AArch64::AEK_RCPC3, AArch64::AEK_THE, AArch64::AEK_D128,
- AArch64::AEK_LSE128, AArch64::AEK_SPECRES2, AArch64::AEK_RASv2,
- AArch64::AEK_ITE, AArch64::AEK_GCS, AArch64::AEK_FPMR,
- AArch64::AEK_FP8, AArch64::AEK_FAMINMAX};
+ AArch64::AEK_CRC, AArch64::AEK_LSE, AArch64::AEK_RDM,
+ AArch64::AEK_CRYPTO, AArch64::AEK_SM4, AArch64::AEK_SHA3,
+ AArch64::AEK_SHA2, AArch64::AEK_AES, AArch64::AEK_DOTPROD,
+ AArch64::AEK_FP, AArch64::AEK_SIMD, AArch64::AEK_FP16,
+ AArch64::AEK_FP16FML, AArch64::AEK_PROFILE, AArch64::AEK_RAS,
+ AArch64::AEK_SVE, AArch64::AEK_SVE2, AArch64::AEK_SVE2AES,
+ AArch64::AEK_SVE2SM4, AArch64::AEK_SVE2SHA3, AArch64::AEK_SVE2BITPERM,
+ AArch64::AEK_RCPC, AArch64::AEK_RAND, AArch64::AEK_MTE,
+ AArch64::AEK_SSBS, AArch64::AEK_SB, AArch64::AEK_PREDRES,
+ AArch64::AEK_BF16, AArch64::AEK_I8MM, AArch64::AEK_F32MM,
+ AArch64::AEK_F64MM, AArch64::AEK_TME, AArch64::AEK_LS64,
+ AArch64::AEK_BRBE, AArch64::AEK_PAUTH, AArch64::AEK_FLAGM,
+ AArch64::AEK_SME, AArch64::AEK_SMEF64F64, AArch64::AEK_SMEI16I64,
+ AArch64::AEK_SME2, AArch64::AEK_HBC, AArch64::AEK_MOPS,
+ AArch64::AEK_PERFMON, AArch64::AEK_SVE2p1, AArch64::AEK_SME2p1,
+ AArch64::AEK_B16B16, AArch64::AEK_SMEF16F16, AArch64::AEK_CSSC,
+ AArch64::AEK_RCPC3, AArch64::AEK_THE, AArch64::AEK_D128,
+ AArch64::AEK_LSE128, AArch64::AEK_SPECRES2, AArch64::AEK_RASv2,
+ AArch64::AEK_ITE, AArch64::AEK_GCS, AArch64::AEK_FPMR,
+ AArch64::AEK_FP8, AArch64::AEK_FAMINMAX, AArch64::AEK_LUT,
+ AArch64::AEK_SME_LUTv2};
std::vector<StringRef> Features;
@@ -1807,6 +1808,8 @@ TEST(TargetParserTest, AArch64ExtensionFeatures) {
EXPECT_TRUE(llvm::is_contained(Features, "+fpmr"));
EXPECT_TRUE(llvm::is_contained(Features, "+fp8"));
EXPECT_TRUE(llvm::is_contained(Features, "+faminmax"));
+ EXPECT_TRUE(llvm::is_contained(Features, "+lut"));
+ EXPECT_TRUE(llvm::is_contained(Features, "+sme-lutv2"));
// Assuming we listed every extension above, this should produce the same
// result. (note that AEK_NONE doesn't have a name so it won't be in the
@@ -1933,6 +1936,8 @@ TEST(TargetParserTest, AArch64ArchExtFeature) {
{"fpmr", "nofpmr", "+fpmr", "-fpmr"},
{"fp8", "nofp8", "+fp8", "-fp8"},
{"faminmax", "nofaminmax", "+faminmax", "-faminmax"},
+ {"lut", "nolut", "+lut", "-lut"},
+ {"sme-lutv2", "nosme-lutv2", "+sme-lutv2", "-sme-lutv2"},
};
for (unsigned i = 0; i < std::size(ArchExt); i++) {
More information about the llvm-commits
mailing list