Skip to content

Commit f73604d

Browse files
CarolineConcattopuja2196
authored andcommitted
[Clang][LLVM][AArch64] Add intrinsic for LUTI4 SME2 instruction (#97755) (#109953)
This patch was reverted because of a failing C test. It now has being solved and can be merged into main again This patch adds these intrinsics: // Variants are also available for: _s8 svuint8x4_t svluti4_zt_u8_x4(uint64_t zt0, svuint8x2_t zn) __arm_streaming __arm_in("zt0"); according to PR#324[1] [1]ARM-software/acle#324
1 parent 33c3eca commit f73604d

File tree

7 files changed

+122
-10
lines changed

7 files changed

+122
-10
lines changed

clang/include/clang/Basic/arm_sme.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,4 +817,9 @@ multiclass ZAReadzArray<string vg_num>{
817817

818818
defm SVREADZ_VG2 : ZAReadzArray<"2">;
819819
defm SVREADZ_VG4 : ZAReadzArray<"4">;
820+
821+
let SMETargetGuard = "sme2,sme-lutv2" in {
822+
def SVLUTI4_ZT_X4 : SInst<"svluti4_zt_{d}_x4", "4i2.u", "cUc", MergeNone, "aarch64_sme_luti4_zt_x4", [IsStreaming, IsInZT0], [ImmCheck<0, ImmCheck0_0>]>;
823+
}
824+
820825
} // let SVETargetGuard = InvalidMode
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
2+
3+
// REQUIRES: aarch64-registered-target
4+
5+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme2 -target-feature +sme-lutv2 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s
6+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme2 -target-feature +sme-lutv2 -disable-O0-optnone -Werror -Wall -emit-llvm -o - -x c++ %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CPP-CHECK
7+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme2 -target-feature +sme-lutv2 -disable-O0-optnone -Werror -Wall -o /dev/null %s
8+
9+
10+
#include <arm_sme.h>
11+
12+
// CHECK-LABEL: define dso_local { <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8> } @test_luti4_zt_u8_x4(
13+
// CHECK-SAME: <vscale x 16 x i8> [[OP_COERCE0:%.*]], <vscale x 16 x i8> [[OP_COERCE1:%.*]]) #[[ATTR0:[0-9]+]] {
14+
// CHECK-NEXT: [[ENTRY:.*:]]
15+
// CHECK-NEXT: [[TMP0:%.*]] = tail call { <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8> } @llvm.aarch64.sme.luti4.zt.x4.nxv16i8(i32 0, <vscale x 16 x i8> [[OP_COERCE0]], <vscale x 16 x i8> [[OP_COERCE1]])
16+
// CHECK-NEXT: ret { <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8> } [[TMP0]]
17+
//
18+
// CPP-CHECK-LABEL: define dso_local { <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8> } @_Z19test_luti4_zt_u8_x411svuint8x2_t(
19+
// CPP-CHECK-SAME: <vscale x 16 x i8> [[OP_COERCE0:%.*]], <vscale x 16 x i8> [[OP_COERCE1:%.*]]) #[[ATTR0:[0-9]+]] {
20+
// CPP-CHECK-NEXT: [[ENTRY:.*:]]
21+
// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8> } @llvm.aarch64.sme.luti4.zt.x4.nxv16i8(i32 0, <vscale x 16 x i8> [[OP_COERCE0]], <vscale x 16 x i8> [[OP_COERCE1]])
22+
// CPP-CHECK-NEXT: ret { <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8> } [[TMP0]]
23+
//
24+
svuint8x4_t test_luti4_zt_u8_x4(svuint8x2_t op) __arm_streaming __arm_in("zt0") {
25+
return svluti4_zt_u8_x4(0, op);
26+
}
27+
28+
// CHECK-LABEL: define dso_local { <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8> } @test_luti4_zt_s8_x4(
29+
// CHECK-SAME: <vscale x 16 x i8> [[OP_COERCE0:%.*]], <vscale x 16 x i8> [[OP_COERCE1:%.*]]) #[[ATTR0]] {
30+
// CHECK-NEXT: [[ENTRY:.*:]]
31+
// CHECK-NEXT: [[TMP0:%.*]] = tail call { <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8> } @llvm.aarch64.sme.luti4.zt.x4.nxv16i8(i32 0, <vscale x 16 x i8> [[OP_COERCE0]], <vscale x 16 x i8> [[OP_COERCE1]])
32+
// CHECK-NEXT: ret { <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8> } [[TMP0]]
33+
//
34+
// CPP-CHECK-LABEL: define dso_local { <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8> } @_Z19test_luti4_zt_s8_x411svuint8x2_t(
35+
// CPP-CHECK-SAME: <vscale x 16 x i8> [[OP_COERCE0:%.*]], <vscale x 16 x i8> [[OP_COERCE1:%.*]]) #[[ATTR0]] {
36+
// CPP-CHECK-NEXT: [[ENTRY:.*:]]
37+
// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8> } @llvm.aarch64.sme.luti4.zt.x4.nxv16i8(i32 0, <vscale x 16 x i8> [[OP_COERCE0]], <vscale x 16 x i8> [[OP_COERCE1]])
38+
// CPP-CHECK-NEXT: ret { <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8> } [[TMP0]]
39+
//
40+
svint8x4_t test_luti4_zt_s8_x4(svuint8x2_t op) __arm_streaming __arm_in("zt0") {
41+
return svluti4_zt_s8_x4(0, op);
42+
}

clang/test/Sema/aarch64-sme2-intrinsics/acle_sme2_imm.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,3 +350,8 @@ void test_svdot_multi_za32_bad_lane(uint32_t slice_base, svuint16_t z_u16,
350350
svsudot_lane_za32_s8_vg1x2(slice_base, z_s8x2, z_u8, 4); // expected-error {{argument value 4 is outside the valid range [0, 3]}}
351351
svsudot_lane_za32_s8_vg1x4(slice_base, z_s8x4, z_u8, 4); // expected-error {{argument value 4 is outside the valid range [0, 3]}}
352352
}
353+
354+
void test_luti4_zt_x4(svuint8x2_t op) __arm_streaming __arm_in("zt0") {
355+
// Check Zt tile 0
356+
svluti4_zt_u8_x4(1, op); // expected-error {{argument value 1 is outside the valid range [0, 0]}}
357+
}

llvm/include/llvm/IR/IntrinsicsAArch64.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3769,6 +3769,12 @@ let TargetPrefix = "aarch64" in {
37693769
: DefaultAttrsIntrinsic<[llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>],
37703770
[llvm_i32_ty, llvm_nxv16i8_ty, llvm_i32_ty],
37713771
[ImmArg<ArgIndex<0>>, ImmArg<ArgIndex<2>>, IntrReadMem]>;
3772+
3773+
def int_aarch64_sme_luti4_zt_x4
3774+
: DefaultAttrsIntrinsic<[llvm_anyvector_ty, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>],
3775+
[llvm_i32_ty, llvm_nxv16i8_ty, llvm_nxv16i8_ty],
3776+
[ImmArg<ArgIndex<0>>, IntrNoMem, IntrHasSideEffects]>;
3777+
37723778

37733779
//
37743780
// Register scaling
@@ -3794,6 +3800,7 @@ let TargetPrefix = "aarch64" in {
37943800
[LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>,
37953801
LLVMVectorOfBitcastsToInt<0>, LLVMVectorOfBitcastsToInt<0>, LLVMVectorOfBitcastsToInt<0>, LLVMVectorOfBitcastsToInt<0>],
37963802
[IntrNoMem]>;
3803+
37973804
}
37983805

37993806
// SVE2.1 - ZIPQ1, ZIPQ2, UZPQ1, UZPQ2

llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -400,8 +400,10 @@ class AArch64DAGToDAGISel : public SelectionDAGISel {
400400
return SelectSVERegRegAddrMode(N, Scale, Base, Offset);
401401
}
402402

403-
void SelectMultiVectorLuti(SDNode *Node, unsigned NumOutVecs, unsigned Opc,
404-
uint32_t MaxImm);
403+
void SelectMultiVectorLutiLane(SDNode *Node, unsigned NumOutVecs,
404+
unsigned Opc, uint32_t MaxImm);
405+
406+
void SelectMultiVectorLuti(SDNode *Node, unsigned NumOutVecs, unsigned Opc);
405407

406408
template <unsigned MaxIdx, unsigned Scale>
407409
bool SelectSMETileSlice(SDValue N, SDValue &Vector, SDValue &Offset) {
@@ -1975,16 +1977,18 @@ void AArch64DAGToDAGISel::SelectFrintFromVT(SDNode *N, unsigned NumVecs,
19751977
SelectUnaryMultiIntrinsic(N, NumVecs, true, Opcode);
19761978
}
19771979

1978-
void AArch64DAGToDAGISel::SelectMultiVectorLuti(SDNode *Node,
1979-
unsigned NumOutVecs,
1980-
unsigned Opc, uint32_t MaxImm) {
1980+
void AArch64DAGToDAGISel::SelectMultiVectorLutiLane(SDNode *Node,
1981+
unsigned NumOutVecs,
1982+
unsigned Opc,
1983+
uint32_t MaxImm) {
19811984
if (ConstantSDNode *Imm = dyn_cast<ConstantSDNode>(Node->getOperand(4)))
19821985
if (Imm->getZExtValue() > MaxImm)
19831986
return;
19841987

19851988
SDValue ZtValue;
19861989
if (!ImmToReg<AArch64::ZT0, 0>(Node->getOperand(2), ZtValue))
19871990
return;
1991+
19881992
SDValue Ops[] = {ZtValue, Node->getOperand(3), Node->getOperand(4)};
19891993
SDLoc DL(Node);
19901994
EVT VT = Node->getValueType(0);
@@ -2003,6 +2007,34 @@ void AArch64DAGToDAGISel::SelectMultiVectorLuti(SDNode *Node,
20032007
CurDAG->RemoveDeadNode(Node);
20042008
}
20052009

2010+
void AArch64DAGToDAGISel::SelectMultiVectorLuti(SDNode *Node,
2011+
unsigned NumOutVecs,
2012+
unsigned Opc) {
2013+
2014+
SDValue ZtValue;
2015+
SmallVector<SDValue, 4> Ops;
2016+
if (!ImmToReg<AArch64::ZT0, 0>(Node->getOperand(2), ZtValue))
2017+
return;
2018+
2019+
Ops.push_back(ZtValue);
2020+
Ops.push_back(createZMulTuple({Node->getOperand(3), Node->getOperand(4)}));
2021+
SDLoc DL(Node);
2022+
EVT VT = Node->getValueType(0);
2023+
2024+
SDNode *Instruction =
2025+
CurDAG->getMachineNode(Opc, DL, {MVT::Untyped, MVT::Other}, Ops);
2026+
SDValue SuperReg = SDValue(Instruction, 0);
2027+
2028+
for (unsigned I = 0; I < NumOutVecs; ++I)
2029+
ReplaceUses(SDValue(Node, I), CurDAG->getTargetExtractSubreg(
2030+
AArch64::zsub0 + I, DL, VT, SuperReg));
2031+
2032+
// Copy chain
2033+
unsigned ChainIdx = NumOutVecs;
2034+
ReplaceUses(SDValue(Node, ChainIdx), SDValue(Instruction, 1));
2035+
CurDAG->RemoveDeadNode(Node);
2036+
}
2037+
20062038
void AArch64DAGToDAGISel::SelectClamp(SDNode *N, unsigned NumVecs,
20072039
unsigned Op) {
20082040
SDLoc DL(N);
@@ -5478,15 +5510,15 @@ void AArch64DAGToDAGISel::Select(SDNode *Node) {
54785510
{AArch64::LUTI2_4ZTZI_B, AArch64::LUTI2_4ZTZI_H,
54795511
AArch64::LUTI2_4ZTZI_S}))
54805512
// Second Immediate must be <= 3:
5481-
SelectMultiVectorLuti(Node, 4, Opc, 3);
5513+
SelectMultiVectorLutiLane(Node, 4, Opc, 3);
54825514
return;
54835515
}
54845516
case Intrinsic::aarch64_sme_luti4_lane_zt_x4: {
54855517
if (auto Opc = SelectOpcodeFromVT<SelectTypeKind::AnyType>(
54865518
Node->getValueType(0),
54875519
{0, AArch64::LUTI4_4ZTZI_H, AArch64::LUTI4_4ZTZI_S}))
54885520
// Second Immediate must be <= 1:
5489-
SelectMultiVectorLuti(Node, 4, Opc, 1);
5521+
SelectMultiVectorLutiLane(Node, 4, Opc, 1);
54905522
return;
54915523
}
54925524
case Intrinsic::aarch64_sme_luti2_lane_zt_x2: {
@@ -5495,7 +5527,7 @@ void AArch64DAGToDAGISel::Select(SDNode *Node) {
54955527
{AArch64::LUTI2_2ZTZI_B, AArch64::LUTI2_2ZTZI_H,
54965528
AArch64::LUTI2_2ZTZI_S}))
54975529
// Second Immediate must be <= 7:
5498-
SelectMultiVectorLuti(Node, 2, Opc, 7);
5530+
SelectMultiVectorLutiLane(Node, 2, Opc, 7);
54995531
return;
55005532
}
55015533
case Intrinsic::aarch64_sme_luti4_lane_zt_x2: {
@@ -5504,7 +5536,11 @@ void AArch64DAGToDAGISel::Select(SDNode *Node) {
55045536
{AArch64::LUTI4_2ZTZI_B, AArch64::LUTI4_2ZTZI_H,
55055537
AArch64::LUTI4_2ZTZI_S}))
55065538
// Second Immediate must be <= 3:
5507-
SelectMultiVectorLuti(Node, 2, Opc, 3);
5539+
SelectMultiVectorLutiLane(Node, 2, Opc, 3);
5540+
return;
5541+
}
5542+
case Intrinsic::aarch64_sme_luti4_zt_x4: {
5543+
SelectMultiVectorLuti(Node, 4, AArch64::LUTI4_4ZZT2Z);
55085544
return;
55095545
}
55105546
}

llvm/lib/Target/AArch64/AArch64SMEInstrInfo.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -940,7 +940,7 @@ defm FAMIN_4Z4Z : sme2_fp_sve_destructive_vector_vg4_multi<"famin", 0b0010101>;
940940

941941
let Predicates = [HasSME2, HasSME_LUTv2] in {
942942
defm MOVT : sme2_movt_zt_to_zt<"movt", 0b0011111>;
943-
def LUTI4_4ZZT2Z : sme2_luti4_vector_vg4<0b00, 0b00,"luti4">;
943+
def LUTI4_4ZZT2Z : sme2_luti4_vector_vg4<0b00, 0b00,"luti4">;
944944
} //[HasSME2, HasSME_LUTv2]
945945

946946
let Predicates = [HasSME2p1, HasSME_LUTv2] in {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
2+
; RUN: llc -verify-machineinstrs -force-streaming < %s | FileCheck %s
3+
4+
target triple = "aarch64-linux"
5+
6+
define {<vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8>} @test_luti4_zt_i8(<vscale x 16 x i8> %v0, <vscale x 16 x i8> %v1) #0 {
7+
; CHECK-LABEL: test_luti4_zt_i8:
8+
; CHECK: // %bb.0:
9+
; CHECK-NEXT: // kill: def $z1 killed $z1 killed $z0_z1 def $z0_z1
10+
; CHECK-NEXT: // kill: def $z0 killed $z0 killed $z0_z1 def $z0_z1
11+
; CHECK-NEXT: luti4 { z0.b - z3.b }, zt0, { z0, z1 }
12+
; CHECK-NEXT: ret
13+
%res = call {<vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8>} @llvm.aarch64.sme.luti4.zt.x4.nxv16i8(i32 0, <vscale x 16 x i8> %v0, <vscale x 16 x i8> %v1)
14+
ret {<vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8>, <vscale x 16 x i8>} %res
15+
}
16+
17+
attributes #0 = { "target-features"="+sme2,+sme-lutv2"}

0 commit comments

Comments
 (0)