Skip to content

Commit 981f080

Browse files
committed
[SVE] Generate overloaded functions for ACLE intrinsics.
The SVE ACLE allows using a short-form for the intrinsics, e.g. the following two declarations generate the same code: svuint32_t svld1(svbool_t, uint32_t const *); svuint32_t svld1_u32(svbool_t, uint32_t const *); using the attribute: __clang_arm_builtin_alias so that any call to svld1(svbool_t, uint32_t const *) will map to __builtin_sve_svld1_u32. Reviewers: SjoerdMeijer, miyuki, efriedma, simon_tatham, rengolin Reviewed By: SjoerdMeijer Tags: #clang Differential Revision: https://reviews.llvm.org/D75861
1 parent 8a36594 commit 981f080

File tree

4 files changed

+166
-5
lines changed

4 files changed

+166
-5
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,8 @@ class TargetArch<list<string> arches> : TargetSpec {
359359
let Arches = arches;
360360
}
361361
def TargetARM : TargetArch<["arm", "thumb", "armeb", "thumbeb"]>;
362+
def TargetAArch64 : TargetArch<["aarch64"]>;
363+
def TargetAnyArm : TargetArch<!listconcat(TargetARM.Arches, TargetAArch64.Arches)>;
362364
def TargetAVR : TargetArch<["avr"]>;
363365
def TargetBPF : TargetArch<["bpfel", "bpfeb"]>;
364366
def TargetMips32 : TargetArch<["mips", "mipsel"]>;
@@ -623,7 +625,7 @@ def Alias : Attr {
623625
let Documentation = [Undocumented];
624626
}
625627

626-
def ArmBuiltinAlias : InheritableAttr, TargetSpecificAttr<TargetARM> {
628+
def ArmBuiltinAlias : InheritableAttr, TargetSpecificAttr<TargetAnyArm> {
627629
let Spellings = [Clang<"__clang_arm_builtin_alias">];
628630
let Args = [IdentifierArgument<"BuiltinName">];
629631
let Subjects = SubjectList<[Function], ErrorDiag>;

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4980,6 +4980,17 @@ static bool ArmCdeAliasValid(unsigned BuiltinID, StringRef AliasName) {
49804980
return ArmBuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);
49814981
}
49824982

4983+
static bool ArmSveAliasValid(unsigned BuiltinID, StringRef AliasName) {
4984+
switch (BuiltinID) {
4985+
default:
4986+
return false;
4987+
#define GET_SVE_BUILTINS
4988+
#define BUILTIN(name, types, attr) case SVE::BI##name:
4989+
#include "clang/Basic/arm_sve_builtins.inc"
4990+
return true;
4991+
}
4992+
}
4993+
49834994
static void handleArmBuiltinAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
49844995
if (!AL.isArgIdent(0)) {
49854996
S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
@@ -4991,8 +5002,10 @@ static void handleArmBuiltinAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
49915002
unsigned BuiltinID = Ident->getBuiltinID();
49925003
StringRef AliasName = cast<FunctionDecl>(D)->getIdentifier()->getName();
49935004

4994-
if (!ArmMveAliasValid(BuiltinID, AliasName) &&
4995-
!ArmCdeAliasValid(BuiltinID, AliasName)) {
5005+
bool IsAArch64 = S.Context.getTargetInfo().getTriple().isAArch64();
5006+
if ((IsAArch64 && !ArmSveAliasValid(BuiltinID, AliasName)) ||
5007+
(!IsAArch64 && !ArmMveAliasValid(BuiltinID, AliasName) &&
5008+
!ArmCdeAliasValid(BuiltinID, AliasName))) {
49965009
S.Diag(AL.getLoc(), diag::err_attribute_arm_builtin_alias);
49975010
return;
49985011
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -fallow-half-arguments-and-returns -S -O1 -Werror -emit-llvm -o - %s -D__ARM_FEATURE_SVE | FileCheck %s
2+
3+
#include <arm_sve.h>
4+
//
5+
// ld1
6+
//
7+
8+
svint8_t test_svld1_s8(svbool_t pg, const int8_t *base)
9+
{
10+
// CHECK-LABEL: test_svld1_s8
11+
// CHECK: <vscale x 16 x i8> @llvm.masked.load.nxv16i8.p0nxv16i8(<vscale x 16 x i8>* %{{.*}}, i32 1, <vscale x 16 x i1> %{{.*}}, <vscale x 16 x i8> zeroinitializer)
12+
return svld1(pg, base);
13+
}
14+
15+
svint16_t test_svld1_s16(svbool_t pg, const int16_t *base)
16+
{
17+
// CHECK-LABEL: test_svld1_s16
18+
// CHECK: <vscale x 8 x i16> @llvm.masked.load.nxv8i16.p0nxv8i16(<vscale x 8 x i16>* %{{.*}}, i32 1, <vscale x 8 x i1> %{{.*}}, <vscale x 8 x i16> zeroinitializer)
19+
return svld1(pg, base);
20+
}
21+
22+
svint32_t test_svld1_s32(svbool_t pg, const int32_t *base)
23+
{
24+
// CHECK-LABEL: test_svld1_s32
25+
// CHECK: <vscale x 4 x i32> @llvm.masked.load.nxv4i32.p0nxv4i32(<vscale x 4 x i32>* %{{.*}}, i32 1, <vscale x 4 x i1> %{{.*}}, <vscale x 4 x i32> zeroinitializer)
26+
return svld1(pg, base);
27+
}
28+
29+
svint64_t test_svld1_s64(svbool_t pg, const int64_t *base)
30+
{
31+
// CHECK-LABEL: test_svld1_s64
32+
// CHECK: <vscale x 2 x i64> @llvm.masked.load.nxv2i64.p0nxv2i64(<vscale x 2 x i64>* %{{.*}}, i32 1, <vscale x 2 x i1> %{{.*}}, <vscale x 2 x i64> zeroinitializer)
33+
return svld1(pg, base);
34+
}
35+
36+
svuint8_t test_svld1_u8(svbool_t pg, const uint8_t *base)
37+
{
38+
// CHECK-LABEL: test_svld1_u8
39+
// CHECK: <vscale x 16 x i8> @llvm.masked.load.nxv16i8.p0nxv16i8(<vscale x 16 x i8>* %{{.*}}, i32 1, <vscale x 16 x i1> %{{.*}}, <vscale x 16 x i8> zeroinitializer)
40+
return svld1(pg, base);
41+
}
42+
43+
svuint16_t test_svld1_u16(svbool_t pg, const uint16_t *base)
44+
{
45+
// CHECK-LABEL: test_svld1_u16
46+
// CHECK: <vscale x 8 x i16> @llvm.masked.load.nxv8i16.p0nxv8i16(<vscale x 8 x i16>* %{{.*}}, i32 1, <vscale x 8 x i1> %{{.*}}, <vscale x 8 x i16> zeroinitializer)
47+
return svld1(pg, base);
48+
}
49+
50+
svuint32_t test_svld1_u32(svbool_t pg, const uint32_t *base)
51+
{
52+
// CHECK-LABEL: test_svld1_u32
53+
// CHECK: <vscale x 4 x i32> @llvm.masked.load.nxv4i32.p0nxv4i32(<vscale x 4 x i32>* %{{.*}}, i32 1, <vscale x 4 x i1> %{{.*}}, <vscale x 4 x i32> zeroinitializer)
54+
return svld1(pg, base);
55+
}
56+
57+
svuint64_t test_svld1_u64(svbool_t pg, const uint64_t *base)
58+
{
59+
// CHECK-LABEL: test_svld1_u64
60+
// CHECK: <vscale x 2 x i64> @llvm.masked.load.nxv2i64.p0nxv2i64(<vscale x 2 x i64>* %{{.*}}, i32 1, <vscale x 2 x i1> %{{.*}}, <vscale x 2 x i64> zeroinitializer)
61+
return svld1(pg, base);
62+
}
63+
64+
svfloat16_t test_svld1_f16(svbool_t pg, const float16_t *base)
65+
{
66+
// CHECK-LABEL: test_svld1_f16
67+
// CHECK: <vscale x 8 x half> @llvm.masked.load.nxv8f16.p0nxv8f16(<vscale x 8 x half>* %{{.*}}, i32 1, <vscale x 8 x i1> %{{.*}}, <vscale x 8 x half> zeroinitializer)
68+
return svld1(pg, base);
69+
}
70+
71+
svfloat32_t test_svld1_f32(svbool_t pg, const float32_t *base)
72+
{
73+
// CHECK-LABEL: test_svld1_f32
74+
// CHECK: <vscale x 4 x float> @llvm.masked.load.nxv4f32.p0nxv4f32(<vscale x 4 x float>* %{{.*}}, i32 1, <vscale x 4 x i1> %{{.*}}, <vscale x 4 x float> zeroinitializer)
75+
return svld1(pg, base);
76+
}
77+
78+
svfloat64_t test_svld1_f64(svbool_t pg, const float64_t *base)
79+
{
80+
// CHECK-LABEL: test_svld1_f64
81+
// CHECK: <vscale x 2 x double> @llvm.masked.load.nxv2f64.p0nxv2f64(<vscale x 2 x double>* %{{.*}}, i32 1, <vscale x 2 x i1> %{{.*}}, <vscale x 2 x double> zeroinitializer)
82+
return svld1(pg, base);
83+
}

clang/utils/TableGen/SveEmitter.cpp

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ class SVEType {
100100
/// string for passing to the BUILTIN() macro in Builtins.def.
101101
std::string builtin_str() const;
102102

103+
/// Return the C/C++ string representation of a type for use in the
104+
/// arm_sve.h header file.
105+
std::string str() const;
106+
103107
private:
104108
/// Creates the type based on the typespec string in TS.
105109
void applyTypespec();
@@ -335,6 +339,45 @@ std::string SVEType::builtin_str() const {
335339
return "q" + utostr(getNumElements() * NumVectors) + S;
336340
}
337341

342+
std::string SVEType::str() const {
343+
if (isPredicatePattern())
344+
return "sv_pattern";
345+
346+
if (isPrefetchOp())
347+
return "sv_prfop";
348+
349+
std::string S;
350+
if (Void)
351+
S += "void";
352+
else {
353+
if (isScalableVector())
354+
S += "sv";
355+
if (!Signed && !Float)
356+
S += "u";
357+
358+
if (Float)
359+
S += "float";
360+
else if (isScalarPredicate())
361+
S += "bool";
362+
else
363+
S += "int";
364+
365+
if (!isScalarPredicate())
366+
S += utostr(ElementBitwidth);
367+
if (!isScalableVector() && isVector())
368+
S += "x" + utostr(getNumElements());
369+
if (NumVectors > 1)
370+
S += "x" + utostr(NumVectors);
371+
S += "_t";
372+
}
373+
374+
if (Constant)
375+
S += " const";
376+
if (Pointer)
377+
S += " *";
378+
379+
return S;
380+
}
338381
void SVEType::applyTypespec() {
339382
for (char I : TS) {
340383
switch (I) {
@@ -515,8 +558,19 @@ void Intrinsic::emitIntrinsic(raw_ostream &OS) const {
515558
<< "(...) __builtin_sve_" << mangleName(ClassS)
516559
<< "(__VA_ARGS__)\n";
517560
} else {
518-
llvm_unreachable("Not yet implemented. Overloaded intrinsics will follow "
519-
"in a future patch");
561+
std::string FullName = mangleName(ClassS);
562+
std::string ProtoName = mangleName(ClassG);
563+
564+
OS << "__aio __attribute__((__clang_arm_builtin_alias("
565+
<< "__builtin_sve_" << FullName << ")))\n";
566+
567+
OS << getTypes()[0].str() << " " << ProtoName << "(";
568+
for (unsigned I = 0; I < getTypes().size() - 1; ++I) {
569+
if (I != 0)
570+
OS << ", ";
571+
OS << getTypes()[I + 1].str();
572+
}
573+
OS << ");\n";
520574
}
521575
}
522576

@@ -559,6 +613,11 @@ void SVEEmitter::createIntrinsic(
559613
Out.push_back(std::make_unique<Intrinsic>(Name, Proto, Merge,
560614
LLVMName, Flags, TS, ClassS,
561615
*this, Guard));
616+
617+
// Also generate the short-form (e.g. svadd_m) for the given type-spec.
618+
if (Intrinsic::isOverloadedIntrinsic(Name))
619+
Out.push_back(std::make_unique<Intrinsic>(
620+
Name, Proto, Merge, LLVMName, Flags, TS, ClassG, *this, Guard));
562621
}
563622
}
564623

@@ -608,6 +667,10 @@ void SVEEmitter::createHeader(raw_ostream &OS) {
608667
OS << "typedef __SVFloat64_t svfloat64_t;\n";
609668
OS << "typedef __SVBool_t svbool_t;\n\n";
610669

670+
OS << "/* Function attributes */\n";
671+
OS << "#define __aio static inline __attribute__((__always_inline__, "
672+
"__nodebug__, __overloadable__))\n\n";
673+
611674
SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
612675
std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
613676
for (auto *R : RV)

0 commit comments

Comments
 (0)