Index: lib/Target/AArch64/AArch64SVEInstrInfo.td =================================================================== --- lib/Target/AArch64/AArch64SVEInstrInfo.td +++ lib/Target/AArch64/AArch64SVEInstrInfo.td @@ -1367,6 +1367,10 @@ defm STNT1H_ZZR_D : sve2_mem_cstnt_vs<0b010, "stnt1h", Z_d, ZPR64>; defm STNT1W_ZZR_D : sve2_mem_cstnt_vs<0b100, "stnt1w", Z_d, ZPR64>; defm STNT1D_ZZR_D : sve2_mem_cstnt_vs<0b110, "stnt1d", Z_d, ZPR64>; + + // SVE table lookup (three sources) + defm TBL_ZZZZ : sve2_int_perm_tbl<"tbl">; + defm TBX_ZZZ : sve2_int_perm_tbx<"tbx">; } let Predicates = [HasSVE2AES] in { Index: lib/Target/AArch64/SVEInstrFormats.td =================================================================== --- lib/Target/AArch64/SVEInstrFormats.td +++ lib/Target/AArch64/SVEInstrFormats.td @@ -700,8 +700,8 @@ (!cast(NAME # _Q) ZPR128:$Zd, FPR128asZPR:$Qn, 0), 2>; } -class sve_int_perm_tbl sz8_64, string asm, ZPRRegOp zprty, - RegisterOperand VecList> +class sve_int_perm_tbl sz8_64, bits<2> opc, string asm, + ZPRRegOp zprty, RegisterOperand VecList> : I<(outs zprty:$Zd), (ins VecList:$Zn, zprty:$Zm), asm, "\t$Zd, $Zn, $Zm", "", @@ -713,16 +713,18 @@ let Inst{23-22} = sz8_64; let Inst{21} = 0b1; let Inst{20-16} = Zm; - let Inst{15-10} = 0b001100; + let Inst{15-13} = 0b001; + let Inst{12-11} = opc; + let Inst{10} = 0b0; let Inst{9-5} = Zn; let Inst{4-0} = Zd; } multiclass sve_int_perm_tbl { - def _B : sve_int_perm_tbl<0b00, asm, ZPR8, Z_b>; - def _H : sve_int_perm_tbl<0b01, asm, ZPR16, Z_h>; - def _S : sve_int_perm_tbl<0b10, asm, ZPR32, Z_s>; - def _D : sve_int_perm_tbl<0b11, asm, ZPR64, Z_d>; + def _B : sve_int_perm_tbl<0b00, 0b10, asm, ZPR8, Z_b>; + def _H : sve_int_perm_tbl<0b01, 0b10, asm, ZPR16, Z_h>; + def _S : sve_int_perm_tbl<0b10, 0b10, asm, ZPR32, Z_s>; + def _D : sve_int_perm_tbl<0b11, 0b10, asm, ZPR64, Z_d>; def : InstAlias(NAME # _B) ZPR8:$Zd, ZPR8:$Zn, ZPR8:$Zm), 0>; @@ -734,6 +736,37 @@ (!cast(NAME # _D) ZPR64:$Zd, ZPR64:$Zn, ZPR64:$Zm), 0>; } +multiclass sve2_int_perm_tbl { + def _B : sve_int_perm_tbl<0b00, 0b01, asm, ZPR8, ZZ_b>; + def _H : sve_int_perm_tbl<0b01, 0b01, asm, ZPR16, ZZ_h>; + def _S : sve_int_perm_tbl<0b10, 0b01, asm, ZPR32, ZZ_s>; + def _D : sve_int_perm_tbl<0b11, 0b01, asm, ZPR64, ZZ_d>; +} + +class sve2_int_perm_tbx sz8_64, string asm, ZPRRegOp zprty> +: I<(outs zprty:$Zd), (ins zprty:$Zn, zprty:$Zm), + asm, "\t$Zd, $Zn, $Zm", + "", + []>, Sched<[]> { + bits<5> Zd; + bits<5> Zm; + bits<5> Zn; + let Inst{31-24} = 0b00000101; + let Inst{23-22} = sz8_64; + let Inst{21} = 0b1; + let Inst{20-16} = Zm; + let Inst{15-10} = 0b001011; + let Inst{9-5} = Zn; + let Inst{4-0} = Zd; +} + +multiclass sve2_int_perm_tbx { + def _B : sve2_int_perm_tbx<0b00, asm, ZPR8>; + def _H : sve2_int_perm_tbx<0b01, asm, ZPR16>; + def _S : sve2_int_perm_tbx<0b10, asm, ZPR32>; + def _D : sve2_int_perm_tbx<0b11, asm, ZPR64>; +} + class sve_int_perm_reverse_z sz8_64, string asm, ZPRRegOp zprty> : I<(outs zprty:$Zd), (ins zprty:$Zn), asm, "\t$Zd, $Zn", Index: test/MC/AArch64/SVE2/tbl-diagnostics.s =================================================================== --- /dev/null +++ test/MC/AArch64/SVE2/tbl-diagnostics.s @@ -0,0 +1,51 @@ +// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+sve2 2>&1 < %s| FileCheck %s + +tbl z0.b, { z1.b, z2.b }, z3.h +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid element width +// CHECK-NEXT: tbl z0.b, { z1.b, z2.b }, z3.h +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: + + +// --------------------------------------------------------------------------// +// Invalid vector list. + +tbl z0.d, { }, z1.d +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector register expected +// CHECK-NEXT: tbl z0.d, { }, z1.d +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: + +tbl z0.d, { z1.d, z2.d, z3.d }, z4.d +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction +// CHECK-NEXT: tbl z0.d, { z1.d, z2.d, z3.d }, z4.d +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: + +tbl z0.d, { z1.d, z2.b }, z3.d +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: mismatched register size suffix +// CHECK-NEXT: tbl z0.d, { z1.d, z2.b }, z3.d +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: + +tbl z0.d, { z1.d, z21.d }, z3.d +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: registers must be sequential +// CHECK-NEXT: tbl z0.d, { z1.d, z21.d }, z3.d +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: + +tbl z0.d, { v0.2d, v1.2d }, z1.d +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction +// CHECK-NEXT: tbl z0.d, { v0.2d, v1.2d }, z1.d +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: + + +// --------------------------------------------------------------------------// +// Negative tests for instructions that are incompatible with movprfx + +movprfx z31.d, p0/z, z6.d +tbl z31.d, { z30.d, z31.d }, z31.d +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: instruction is unpredictable when following a movprfx, suggest replacing movprfx with mov +// CHECK-NEXT: tbl z31.d, { z30.d, z31.d }, z31.d +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: + +movprfx z31, z6 +tbl z31.d, { z30.d, z31.d }, z31.d +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: instruction is unpredictable when following a movprfx, suggest replacing movprfx with mov +// CHECK-NEXT: tbl z31.d, { z30.d, z31.d }, z31.d +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: Index: test/MC/AArch64/SVE2/tbl.s =================================================================== --- /dev/null +++ test/MC/AArch64/SVE2/tbl.s @@ -0,0 +1,32 @@ +// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sve2 < %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=+sve2 < %s \ +// RUN: | llvm-objdump -d -mattr=+sve2 - | FileCheck %s --check-prefix=CHECK-INST +// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sve2 < %s \ +// RUN: | llvm-objdump -d - | FileCheck %s --check-prefix=CHECK-UNKNOWN + +tbl z28.b, { z29.b, z30.b }, z31.b +// CHECK-INST: tbl z28.b, { z29.b, z30.b }, z31.b +// CHECK-ENCODING: [0xbc,0x2b,0x3f,0x05] +// CHECK-ERROR: instruction requires: sve2 +// CHECK-UNKNOWN: bc 2b 3f 05 + +tbl z28.h, { z29.h, z30.h }, z31.h +// CHECK-INST: tbl z28.h, { z29.h, z30.h }, z31.h +// CHECK-ENCODING: [0xbc,0x2b,0x7f,0x05] +// CHECK-ERROR: instruction requires: sve2 +// CHECK-UNKNOWN: bc 2b 7f 05 + +tbl z28.s, { z29.s, z30.s }, z31.s +// CHECK-INST: tbl z28.s, { z29.s, z30.s }, z31.s +// CHECK-ENCODING: [0xbc,0x2b,0xbf,0x05] +// CHECK-ERROR: instruction requires: sve2 +// CHECK-UNKNOWN: bc 2b bf 05 + +tbl z28.d, { z29.d, z30.d }, z31.d +// CHECK-INST: tbl z28.d, { z29.d, z30.d }, z31.d +// CHECK-ENCODING: [0xbc,0x2b,0xff,0x05] +// CHECK-ERROR: instruction requires: sve2 +// CHECK-UNKNOWN: bc 2b ff 05 Index: test/MC/AArch64/SVE2/tbx-diagnostics.s =================================================================== --- /dev/null +++ test/MC/AArch64/SVE2/tbx-diagnostics.s @@ -0,0 +1,22 @@ +// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+sve2 2>&1 < %s| FileCheck %s + +tbx z0.b, z1.b, z2.h +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid element width +// CHECK-NEXT: tbx z0.b, z1.b, z2.h +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: + + +// --------------------------------------------------------------------------// +// Negative tests for instructions that are incompatible with movprfx + +movprfx z31.d, p0/z, z6.d +tbx z31.d, z31.d, z31.d +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: instruction is unpredictable when following a movprfx, suggest replacing movprfx with mov +// CHECK-NEXT: tbx z31.d, z31.d, z31.d +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: + +movprfx z31, z6 +tbx z31.d, z31.d, z31.d +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: instruction is unpredictable when following a movprfx, suggest replacing movprfx with mov +// CHECK-NEXT: tbx z31.d, z31.d, z31.d +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: Index: test/MC/AArch64/SVE2/tbx.s =================================================================== --- /dev/null +++ test/MC/AArch64/SVE2/tbx.s @@ -0,0 +1,32 @@ +// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sve2 < %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=+sve2 < %s \ +// RUN: | llvm-objdump -d -mattr=+sve2 - | FileCheck %s --check-prefix=CHECK-INST +// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sve2 < %s \ +// RUN: | llvm-objdump -d - | FileCheck %s --check-prefix=CHECK-UNKNOWN + +tbx z31.b, z31.b, z31.b +// CHECK-INST: tbx z31.b, z31.b, z31.b +// CHECK-ENCODING: [0xff,0x2f,0x3f,0x05] +// CHECK-ERROR: instruction requires: sve2 +// CHECK-UNKNOWN: ff 2f 3f 05 + +tbx z31.h, z31.h, z31.h +// CHECK-INST: tbx z31.h, z31.h, z31.h +// CHECK-ENCODING: [0xff,0x2f,0x7f,0x05] +// CHECK-ERROR: instruction requires: sve2 +// CHECK-UNKNOWN: ff 2f 7f 05 + +tbx z31.s, z31.s, z31.s +// CHECK-INST: tbx z31.s, z31.s, z31.s +// CHECK-ENCODING: [0xff,0x2f,0xbf,0x05] +// CHECK-ERROR: instruction requires: sve2 +// CHECK-UNKNOWN: ff 2f bf 05 + +tbx z31.d, z31.d, z31.d +// CHECK-INST: tbx z31.d, z31.d, z31.d +// CHECK-ENCODING: [0xff,0x2f,0xff,0x05] +// CHECK-ERROR: instruction requires: sve2 +// CHECK-UNKNOWN: ff 2f ff 05