Skip to content

Commit 03f419f

Browse files
committed
[SveEmitter] IsInsertOp1SVALL and builtins for svqdec[bhwd] and svqinc[bhwd]
Some ACLE builtins leave out the argument to specify the predicate pattern, which is expected to be expanded to an SV_ALL pattern. This patch adds the flag IsInsertOp1SVALL to insert SV_ALL as the second operand. Reviewers: efriedma, SjoerdMeijer Reviewed By: SjoerdMeijer Tags: #clang Differential Revision: https://reviews.llvm.org/D78401
1 parent b160e9e commit 03f419f

20 files changed

+1976
-124
lines changed

clang/include/clang/Basic/TargetBuiltins.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ namespace clang {
241241
bool isPrefetch() const { return Flags & IsPrefetch; }
242242
bool isReverseCompare() const { return Flags & ReverseCompare; }
243243
bool isAppendSVALL() const { return Flags & IsAppendSVALL; }
244+
bool isInsertOp1SVALL() const { return Flags & IsInsertOp1SVALL; }
244245

245246
uint64_t getBits() const { return Flags; }
246247
bool isFlagSet(uint64_t Flag) const { return Flags & Flag; }

clang/include/clang/Basic/arm_sve.td

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
// d: default
6565
// c: const pointer type
6666
// P: predicate type
67+
// s: scalar of element type
6768
// a: scalar of element type (splat to vector type)
6869
// e: 1/2 width unsigned elements, 2x element count
6970
// h: 1/2 width elements, 2x element count
@@ -182,6 +183,7 @@ def IsOverloadCvt : FlagType<0x00800000>; // Use {typeof(operand0),
182183
def OverloadKindMask : FlagType<0x00E00000>; // When the masked values are all '0', the default type is used as overload type.
183184
def IsByteIndexed : FlagType<0x01000000>;
184185
def IsAppendSVALL : FlagType<0x02000000>; // Appends SV_ALL as the last operand.
186+
def IsInsertOp1SVALL : FlagType<0x04000000>; // Inserts SV_ALL as the second operand.
185187
def IsPrefetch : FlagType<0x08000000>; // Contiguous prefetches.
186188
def ReverseCompare : FlagType<0x20000000>; // Compare operands must be swapped.
187189

@@ -827,11 +829,6 @@ def SVCVTXNT_F32 : SInst<"svcvtxnt_f32[_f64]", "MMPd", "d", MergeOp1, "aarch6
827829
def SVCADD_M : SInst<"svcadd[_{d}]", "dPddi", "hfd", MergeOp1, "aarch64_sve_fcadd", [], [ImmCheck<3, ImmCheckComplexRot90_270>]>;
828830
def SVCMLA_M : SInst<"svcmla[_{d}]", "dPdddi", "hfd", MergeOp1, "aarch64_sve_fcmla", [], [ImmCheck<4, ImmCheckComplexRotAll90>]>;
829831

830-
////////////////////////////////////////////////////////////////////////////////
831-
// Saturating scalar arithmetic
832-
def SVQDECH_S : SInst<"svqdech_pat[_{d}]", "ddIi", "s", MergeNone, "aarch64_sve_sqdech", [], [ImmCheck<2, ImmCheck1_16>]>;
833-
def SVQDECH_U : SInst<"svqdech_pat[_{d}]", "ddIi", "Us", MergeNone, "aarch64_sve_uqdech", [], [ImmCheck<2, ImmCheck1_16>]>;
834-
835832

836833
////////////////////////////////////////////////////////////////////////////////
837834
// Predicate creation
@@ -853,6 +850,55 @@ def SVCNTB : SInst<"svcntb", "n", "", MergeNone, "aarch64_sve_cntb", [IsAppendSV
853850
def SVCNTH : SInst<"svcnth", "n", "", MergeNone, "aarch64_sve_cnth", [IsAppendSVALL, IsOverloadNone]>;
854851
def SVCNTW : SInst<"svcntw", "n", "", MergeNone, "aarch64_sve_cntw", [IsAppendSVALL, IsOverloadNone]>;
855852
def SVCNTD : SInst<"svcntd", "n", "", MergeNone, "aarch64_sve_cntd", [IsAppendSVALL, IsOverloadNone]>;
853+
854+
////////////////////////////////////////////////////////////////////////////////
855+
// Saturating scalar arithmetic
856+
857+
class sat_type<string u, string t> { string U = u; string T = t; }
858+
def SignedByte : sat_type<"", "c">;
859+
def SignedHalf : sat_type<"", "s">;
860+
def SignedWord : sat_type<"", "i">;
861+
def SignedDoubleWord : sat_type<"", "l">;
862+
def UnsignedByte : sat_type<"U", "Uc">;
863+
def UnsignedHalf : sat_type<"U", "Us">;
864+
def UnsignedWord : sat_type<"U", "Ui">;
865+
def UnsignedDoubleWord : sat_type<"U", "Ul">;
866+
867+
multiclass SInst_SAT1<string name, string intrinsic, sat_type type> {
868+
def _N32 : SInst<name # "_pat[_n_{d}]", "ssIi", type.U # "i", MergeNone, intrinsic # "_n32", [IsOverloadNone], [ImmCheck<2, ImmCheck1_16>]>;
869+
def _N64 : SInst<name # "_pat[_n_{d}]", "ssIi", type.U # "l", MergeNone, intrinsic # "_n64", [IsOverloadNone], [ImmCheck<2, ImmCheck1_16>]>;
870+
def _N32_ALL : SInst<name # "[_n_{d}]", "ssi", type.U # "i", MergeNone, intrinsic # "_n32", [IsOverloadNone, IsInsertOp1SVALL], [ImmCheck<1, ImmCheck1_16>]>;
871+
def _N64_ALL : SInst<name # "[_n_{d}]", "ssi", type.U # "l", MergeNone, intrinsic # "_n64", [IsOverloadNone, IsInsertOp1SVALL], [ImmCheck<1, ImmCheck1_16>]>;
872+
}
873+
874+
multiclass SInst_SAT2<string name, string intrinsic, sat_type type> {
875+
def "" : SInst<name # "_pat[_{d}]", "ddIi", type.T, MergeNone, intrinsic, [], [ImmCheck<2, ImmCheck1_16>]>;
876+
def _ALL : SInst<name # "[_{d}]", "ddi", type.T, MergeNone, intrinsic, [IsInsertOp1SVALL], [ImmCheck<1, ImmCheck1_16>]>;
877+
878+
def _N32 : SInst<name # "_pat[_n_{d}]", "ssIi", type.U # "i", MergeNone, intrinsic # "_n32", [IsOverloadNone], [ImmCheck<2, ImmCheck1_16>]>;
879+
def _N64 : SInst<name # "_pat[_n_{d}]", "ssIi", type.U # "l", MergeNone, intrinsic # "_n64", [IsOverloadNone], [ImmCheck<2, ImmCheck1_16>]>;
880+
def _N32_ALL : SInst<name # "[_n_{d}]", "ssi", type.U # "i", MergeNone, intrinsic # "_n32", [IsOverloadNone, IsInsertOp1SVALL], [ImmCheck<1, ImmCheck1_16>]>;
881+
def _N64_ALL : SInst<name # "[_n_{d}]", "ssi", type.U # "l", MergeNone, intrinsic # "_n64", [IsOverloadNone, IsInsertOp1SVALL], [ImmCheck<1, ImmCheck1_16>]>;
882+
}
883+
884+
defm SVQDECB_S : SInst_SAT1<"svqdecb", "aarch64_sve_sqdecb", SignedByte>;
885+
defm SVQDECB_U : SInst_SAT1<"svqdecb", "aarch64_sve_uqdecb", UnsignedByte>;
886+
defm SVQDECH_S : SInst_SAT2<"svqdech", "aarch64_sve_sqdech", SignedHalf>;
887+
defm SVQDECH_U : SInst_SAT2<"svqdech", "aarch64_sve_uqdech", UnsignedHalf>;
888+
defm SVQDECW_S : SInst_SAT2<"svqdecw", "aarch64_sve_sqdecw", SignedWord>;
889+
defm SVQDECW_U : SInst_SAT2<"svqdecw", "aarch64_sve_uqdecw", UnsignedWord>;
890+
defm SVQDECD_S : SInst_SAT2<"svqdecd", "aarch64_sve_sqdecd", SignedDoubleWord>;
891+
defm SVQDECD_U : SInst_SAT2<"svqdecd", "aarch64_sve_uqdecd", UnsignedDoubleWord>;
892+
893+
defm SVQINCB_S : SInst_SAT1<"svqincb", "aarch64_sve_sqincb", SignedByte>;
894+
defm SVQINCB_U : SInst_SAT1<"svqincb", "aarch64_sve_uqincb", UnsignedByte>;
895+
defm SVQINCH_S : SInst_SAT2<"svqinch", "aarch64_sve_sqinch", SignedHalf>;
896+
defm SVQINCH_U : SInst_SAT2<"svqinch", "aarch64_sve_uqinch", UnsignedHalf>;
897+
defm SVQINCW_S : SInst_SAT2<"svqincw", "aarch64_sve_sqincw", SignedWord>;
898+
defm SVQINCW_U : SInst_SAT2<"svqincw", "aarch64_sve_uqincw", UnsignedWord>;
899+
defm SVQINCD_S : SInst_SAT2<"svqincd", "aarch64_sve_sqincd", SignedDoubleWord>;
900+
defm SVQINCD_U : SInst_SAT2<"svqincd", "aarch64_sve_uqincd", UnsignedDoubleWord>;
901+
856902
////////////////////////////////////////////////////////////////////////////////
857903
// Integer arithmetic
858904
def SVDOT_LANE_S : SInst<"svdot_lane[_{d}]", "ddqqi", "il", MergeNone, "aarch64_sve_sdot_lane", [], [ImmCheck<3, ImmCheckLaneIndexDot, 2>]>;

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7913,6 +7913,8 @@ Value *CodeGenFunction::EmitAArch64SVEBuiltinExpr(unsigned BuiltinID,
79137913
// pattern, which is expected to be expanded to an SV_ALL pattern.
79147914
if (TypeFlags.isAppendSVALL())
79157915
Ops.push_back(Builder.getInt32(/*SV_ALL*/ 31));
7916+
if (TypeFlags.isInsertOp1SVALL())
7917+
Ops.insert(&Ops[1], Builder.getInt32(/*SV_ALL*/ 31));
79167918

79177919
// Predicates must match the main datatype.
79187920
for (unsigned i = 0, e = Ops.size(); i != e; ++i)
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -triple aarch64-none-linux-gnu -target-feature +sve -fallow-half-arguments-and-returns -S -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s
2+
// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sve -fallow-half-arguments-and-returns -S -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s
3+
4+
#include <arm_sve.h>
5+
6+
#ifdef SVE_OVERLOADED_FORMS
7+
// A simple used,unused... macro, long enough to represent any SVE builtin.
8+
#define SVE_ACLE_FUNC(A1,A2_UNUSED,A3,A4_UNUSED) A1##A3
9+
#else
10+
#define SVE_ACLE_FUNC(A1,A2,A3,A4) A1##A2##A3##A4
11+
#endif
12+
13+
int32_t test_svqdecb_n_s32(int32_t op)
14+
{
15+
// CHECK-LABEL: test_svqdecb_n_s32
16+
// CHECK: %[[INTRINSIC:.*]] = call i32 @llvm.aarch64.sve.sqdecb.n32(i32 %op, i32 31, i32 1)
17+
// CHECK: ret i32 %[[INTRINSIC]]
18+
return SVE_ACLE_FUNC(svqdecb,_n_s32,,)(op, 1);
19+
}
20+
21+
int32_t test_svqdecb_n_s32_1(int32_t op)
22+
{
23+
// CHECK-LABEL: test_svqdecb_n_s32_1
24+
// CHECK: %[[INTRINSIC:.*]] = call i32 @llvm.aarch64.sve.sqdecb.n32(i32 %op, i32 31, i32 16)
25+
// CHECK: ret i32 %[[INTRINSIC]]
26+
return SVE_ACLE_FUNC(svqdecb,_n_s32,,)(op, 16);
27+
}
28+
29+
int64_t test_svqdecb_n_s64(int64_t op)
30+
{
31+
// CHECK-LABEL: test_svqdecb_n_s64
32+
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.sqdecb.n64(i64 %op, i32 31, i32 1)
33+
// CHECK: ret i64 %[[INTRINSIC]]
34+
return SVE_ACLE_FUNC(svqdecb,_n_s64,,)(op, 1);
35+
}
36+
37+
uint32_t test_svqdecb_n_u32(uint32_t op)
38+
{
39+
// CHECK-LABEL: test_svqdecb_n_u32
40+
// CHECK: %[[INTRINSIC:.*]] = call i32 @llvm.aarch64.sve.uqdecb.n32(i32 %op, i32 31, i32 16)
41+
// CHECK: ret i32 %[[INTRINSIC]]
42+
return SVE_ACLE_FUNC(svqdecb,_n_u32,,)(op, 16);
43+
}
44+
45+
uint64_t test_svqdecb_n_u64(uint64_t op)
46+
{
47+
// CHECK-LABEL: test_svqdecb_n_u64
48+
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.uqdecb.n64(i64 %op, i32 31, i32 1)
49+
// CHECK: ret i64 %[[INTRINSIC]]
50+
return SVE_ACLE_FUNC(svqdecb,_n_u64,,)(op, 1);
51+
}
52+
53+
int32_t test_svqdecb_pat_n_s32(int32_t op)
54+
{
55+
// CHECK-LABEL: test_svqdecb_pat_n_s32
56+
// CHECK: %[[INTRINSIC:.*]] = call i32 @llvm.aarch64.sve.sqdecb.n32(i32 %op, i32 0, i32 16)
57+
// CHECK: ret i32 %[[INTRINSIC]]
58+
return SVE_ACLE_FUNC(svqdecb_pat,_n_s32,,)(op, SV_POW2, 16);
59+
}
60+
61+
int64_t test_svqdecb_pat_n_s64(int64_t op)
62+
{
63+
// CHECK-LABEL: test_svqdecb_pat_n_s64
64+
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.sqdecb.n64(i64 %op, i32 1, i32 1)
65+
// CHECK: ret i64 %[[INTRINSIC]]
66+
return SVE_ACLE_FUNC(svqdecb_pat,_n_s64,,)(op, SV_VL1, 1);
67+
}
68+
69+
uint32_t test_svqdecb_pat_n_u32(uint32_t op)
70+
{
71+
// CHECK-LABEL: test_svqdecb_pat_n_u32
72+
// CHECK: %[[INTRINSIC:.*]] = call i32 @llvm.aarch64.sve.uqdecb.n32(i32 %op, i32 2, i32 16)
73+
// CHECK: ret i32 %[[INTRINSIC]]
74+
return SVE_ACLE_FUNC(svqdecb_pat,_n_u32,,)(op, SV_VL2, 16);
75+
}
76+
77+
uint64_t test_svqdecb_pat_n_u64(uint64_t op)
78+
{
79+
// CHECK-LABEL: test_svqdecb_pat_n_u64
80+
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.uqdecb.n64(i64 %op, i32 3, i32 1)
81+
// CHECK: ret i64 %[[INTRINSIC]]
82+
return SVE_ACLE_FUNC(svqdecb_pat,_n_u64,,)(op, SV_VL3, 1);
83+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -triple aarch64-none-linux-gnu -target-feature +sve -fallow-half-arguments-and-returns -S -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s
2+
// RUN: %clang_cc1 -D__ARM_FEATURE_SVE -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sve -fallow-half-arguments-and-returns -S -O1 -Werror -Wall -emit-llvm -o - %s | FileCheck %s
3+
4+
#include <arm_sve.h>
5+
6+
#ifdef SVE_OVERLOADED_FORMS
7+
// A simple used,unused... macro, long enough to represent any SVE builtin.
8+
#define SVE_ACLE_FUNC(A1,A2_UNUSED,A3,A4_UNUSED) A1##A3
9+
#else
10+
#define SVE_ACLE_FUNC(A1,A2,A3,A4) A1##A2##A3##A4
11+
#endif
12+
13+
int32_t test_svqdecd_n_s32(int32_t op)
14+
{
15+
// CHECK-LABEL: test_svqdecd_n_s32
16+
// CHECK: %[[INTRINSIC:.*]] = call i32 @llvm.aarch64.sve.sqdecd.n32(i32 %op, i32 31, i32 1)
17+
// CHECK: ret i32 %[[INTRINSIC]]
18+
return SVE_ACLE_FUNC(svqdecd,_n_s32,,)(op, 1);
19+
}
20+
21+
int32_t test_svqdecd_n_s32_1(int32_t op)
22+
{
23+
// CHECK-LABEL: test_svqdecd_n_s32_1
24+
// CHECK: %[[INTRINSIC:.*]] = call i32 @llvm.aarch64.sve.sqdecd.n32(i32 %op, i32 31, i32 16)
25+
// CHECK: ret i32 %[[INTRINSIC]]
26+
return SVE_ACLE_FUNC(svqdecd,_n_s32,,)(op, 16);
27+
}
28+
29+
int64_t test_svqdecd_n_s64(int64_t op)
30+
{
31+
// CHECK-LABEL: test_svqdecd_n_s64
32+
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.sqdecd.n64(i64 %op, i32 31, i32 1)
33+
// CHECK: ret i64 %[[INTRINSIC]]
34+
return SVE_ACLE_FUNC(svqdecd,_n_s64,,)(op, 1);
35+
}
36+
37+
uint32_t test_svqdecd_n_u32(uint32_t op)
38+
{
39+
// CHECK-LABEL: test_svqdecd_n_u32
40+
// CHECK: %[[INTRINSIC:.*]] = call i32 @llvm.aarch64.sve.uqdecd.n32(i32 %op, i32 31, i32 16)
41+
// CHECK: ret i32 %[[INTRINSIC]]
42+
return SVE_ACLE_FUNC(svqdecd,_n_u32,,)(op, 16);
43+
}
44+
45+
uint64_t test_svqdecd_n_u64(uint64_t op)
46+
{
47+
// CHECK-LABEL: test_svqdecd_n_u64
48+
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.uqdecd.n64(i64 %op, i32 31, i32 1)
49+
// CHECK: ret i64 %[[INTRINSIC]]
50+
return SVE_ACLE_FUNC(svqdecd,_n_u64,,)(op, 1);
51+
}
52+
53+
int32_t test_svqdecd_pat_n_s32(int32_t op)
54+
{
55+
// CHECK-LABEL: test_svqdecd_pat_n_s32
56+
// CHECK: %[[INTRINSIC:.*]] = call i32 @llvm.aarch64.sve.sqdecd.n32(i32 %op, i32 4, i32 16)
57+
// CHECK: ret i32 %[[INTRINSIC]]
58+
return SVE_ACLE_FUNC(svqdecd_pat,_n_s32,,)(op, SV_VL4, 16);
59+
}
60+
61+
int64_t test_svqdecd_pat_n_s64(int64_t op)
62+
{
63+
// CHECK-LABEL: test_svqdecd_pat_n_s64
64+
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.sqdecd.n64(i64 %op, i32 5, i32 1)
65+
// CHECK: ret i64 %[[INTRINSIC]]
66+
return SVE_ACLE_FUNC(svqdecd_pat,_n_s64,,)(op, SV_VL5, 1);
67+
}
68+
69+
uint32_t test_svqdecd_pat_n_u32(uint32_t op)
70+
{
71+
// CHECK-LABEL: test_svqdecd_pat_n_u32
72+
// CHECK: %[[INTRINSIC:.*]] = call i32 @llvm.aarch64.sve.uqdecd.n32(i32 %op, i32 6, i32 16)
73+
// CHECK: ret i32 %[[INTRINSIC]]
74+
return SVE_ACLE_FUNC(svqdecd_pat,_n_u32,,)(op, SV_VL6, 16);
75+
}
76+
77+
uint64_t test_svqdecd_pat_n_u64(uint64_t op)
78+
{
79+
// CHECK-LABEL: test_svqdecd_pat_n_u64
80+
// CHECK: %[[INTRINSIC:.*]] = call i64 @llvm.aarch64.sve.uqdecd.n64(i64 %op, i32 7, i32 1)
81+
// CHECK: ret i64 %[[INTRINSIC]]
82+
return SVE_ACLE_FUNC(svqdecd_pat,_n_u64,,)(op, SV_VL7, 1);
83+
}
84+
85+
svint64_t test_svqdecd_s64(svint64_t op)
86+
{
87+
// CHECK-LABEL: test_svqdecd_s64
88+
// CHECK: %[[INTRINSIC:.*]] = call <vscale x 2 x i64> @llvm.aarch64.sve.sqdecd.nxv2i64(<vscale x 2 x i64> %op, i32 31, i32 16)
89+
// CHECK: ret <vscale x 2 x i64> %[[INTRINSIC]]
90+
return SVE_ACLE_FUNC(svqdecd,_s64,,)(op, 16);
91+
}
92+
93+
svuint64_t test_svqdecd_u64(svuint64_t op)
94+
{
95+
// CHECK-LABEL: test_svqdecd_u64
96+
// CHECK: %[[INTRINSIC:.*]] = call <vscale x 2 x i64> @llvm.aarch64.sve.uqdecd.nxv2i64(<vscale x 2 x i64> %op, i32 31, i32 1)
97+
// CHECK: ret <vscale x 2 x i64> %[[INTRINSIC]]
98+
return SVE_ACLE_FUNC(svqdecd,_u64,,)(op, 1);
99+
}
100+
101+
svint64_t test_svqdecd_pat_s64(svint64_t op)
102+
{
103+
// CHECK-LABEL: test_svqdecd_pat_s64
104+
// CHECK: %[[INTRINSIC:.*]] = call <vscale x 2 x i64> @llvm.aarch64.sve.sqdecd.nxv2i64(<vscale x 2 x i64> %op, i32 8, i32 16)
105+
// CHECK: ret <vscale x 2 x i64> %[[INTRINSIC]]
106+
return SVE_ACLE_FUNC(svqdecd_pat,_s64,,)(op, SV_VL8, 16);
107+
}
108+
109+
svuint64_t test_svqdecd_pat_u64(svuint64_t op)
110+
{
111+
// CHECK-LABEL: test_svqdecd_pat_u64
112+
// CHECK: %[[INTRINSIC:.*]] = call <vscale x 2 x i64> @llvm.aarch64.sve.uqdecd.nxv2i64(<vscale x 2 x i64> %op, i32 9, i32 1)
113+
// CHECK: ret <vscale x 2 x i64> %[[INTRINSIC]]
114+
return SVE_ACLE_FUNC(svqdecd_pat,_u64,,)(op, SV_VL16, 1);
115+
}

0 commit comments

Comments
 (0)