[clang] 981f080 - [SVE] Generate overloaded functions for ACLE intrinsics.
Sander de Smalen via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 19 02:36:48 PDT 2020
Author: Sander de Smalen
Date: 2020-03-19T09:36:23Z
New Revision: 981f0802b37597975606d2b5f5bbc25974c4c3df
URL: https://github.com/llvm/llvm-project/commit/981f0802b37597975606d2b5f5bbc25974c4c3df
DIFF: https://github.com/llvm/llvm-project/commit/981f0802b37597975606d2b5f5bbc25974c4c3df.diff
LOG: [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
Added:
clang/test/CodeGen/aarch64-sve-intrinsics/acle_sve_ld1_shortform.c
Modified:
clang/include/clang/Basic/Attr.td
clang/lib/Sema/SemaDeclAttr.cpp
clang/utils/TableGen/SveEmitter.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index a0d521d17d0f..10ed63d7ccae 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -359,6 +359,8 @@ class TargetArch<list<string> arches> : TargetSpec {
let Arches = arches;
}
def TargetARM : TargetArch<["arm", "thumb", "armeb", "thumbeb"]>;
+def TargetAArch64 : TargetArch<["aarch64"]>;
+def TargetAnyArm : TargetArch<!listconcat(TargetARM.Arches, TargetAArch64.Arches)>;
def TargetAVR : TargetArch<["avr"]>;
def TargetBPF : TargetArch<["bpfel", "bpfeb"]>;
def TargetMips32 : TargetArch<["mips", "mipsel"]>;
@@ -623,7 +625,7 @@ def Alias : Attr {
let Documentation = [Undocumented];
}
-def ArmBuiltinAlias : InheritableAttr, TargetSpecificAttr<TargetARM> {
+def ArmBuiltinAlias : InheritableAttr, TargetSpecificAttr<TargetAnyArm> {
let Spellings = [Clang<"__clang_arm_builtin_alias">];
let Args = [IdentifierArgument<"BuiltinName">];
let Subjects = SubjectList<[Function], ErrorDiag>;
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 67b7fa6cb46f..393fdcb479d5 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -4980,6 +4980,17 @@ static bool ArmCdeAliasValid(unsigned BuiltinID, StringRef AliasName) {
return ArmBuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames);
}
+static bool ArmSveAliasValid(unsigned BuiltinID, StringRef AliasName) {
+ switch (BuiltinID) {
+ default:
+ return false;
+#define GET_SVE_BUILTINS
+#define BUILTIN(name, types, attr) case SVE::BI##name:
+#include "clang/Basic/arm_sve_builtins.inc"
+ return true;
+ }
+}
+
static void handleArmBuiltinAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!AL.isArgIdent(0)) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
@@ -4991,8 +5002,10 @@ static void handleArmBuiltinAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
unsigned BuiltinID = Ident->getBuiltinID();
StringRef AliasName = cast<FunctionDecl>(D)->getIdentifier()->getName();
- if (!ArmMveAliasValid(BuiltinID, AliasName) &&
- !ArmCdeAliasValid(BuiltinID, AliasName)) {
+ bool IsAArch64 = S.Context.getTargetInfo().getTriple().isAArch64();
+ if ((IsAArch64 && !ArmSveAliasValid(BuiltinID, AliasName)) ||
+ (!IsAArch64 && !ArmMveAliasValid(BuiltinID, AliasName) &&
+ !ArmCdeAliasValid(BuiltinID, AliasName))) {
S.Diag(AL.getLoc(), diag::err_attribute_arm_builtin_alias);
return;
}
diff --git a/clang/test/CodeGen/aarch64-sve-intrinsics/acle_sve_ld1_shortform.c b/clang/test/CodeGen/aarch64-sve-intrinsics/acle_sve_ld1_shortform.c
new file mode 100644
index 000000000000..90258f00de43
--- /dev/null
+++ b/clang/test/CodeGen/aarch64-sve-intrinsics/acle_sve_ld1_shortform.c
@@ -0,0 +1,83 @@
+// 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
+
+#include <arm_sve.h>
+//
+// ld1
+//
+
+svint8_t test_svld1_s8(svbool_t pg, const int8_t *base)
+{
+ // CHECK-LABEL: test_svld1_s8
+ // 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)
+ return svld1(pg, base);
+}
+
+svint16_t test_svld1_s16(svbool_t pg, const int16_t *base)
+{
+ // CHECK-LABEL: test_svld1_s16
+ // 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)
+ return svld1(pg, base);
+}
+
+svint32_t test_svld1_s32(svbool_t pg, const int32_t *base)
+{
+ // CHECK-LABEL: test_svld1_s32
+ // 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)
+ return svld1(pg, base);
+}
+
+svint64_t test_svld1_s64(svbool_t pg, const int64_t *base)
+{
+ // CHECK-LABEL: test_svld1_s64
+ // 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)
+ return svld1(pg, base);
+}
+
+svuint8_t test_svld1_u8(svbool_t pg, const uint8_t *base)
+{
+ // CHECK-LABEL: test_svld1_u8
+ // 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)
+ return svld1(pg, base);
+}
+
+svuint16_t test_svld1_u16(svbool_t pg, const uint16_t *base)
+{
+ // CHECK-LABEL: test_svld1_u16
+ // 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)
+ return svld1(pg, base);
+}
+
+svuint32_t test_svld1_u32(svbool_t pg, const uint32_t *base)
+{
+ // CHECK-LABEL: test_svld1_u32
+ // 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)
+ return svld1(pg, base);
+}
+
+svuint64_t test_svld1_u64(svbool_t pg, const uint64_t *base)
+{
+ // CHECK-LABEL: test_svld1_u64
+ // 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)
+ return svld1(pg, base);
+}
+
+svfloat16_t test_svld1_f16(svbool_t pg, const float16_t *base)
+{
+ // CHECK-LABEL: test_svld1_f16
+ // 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)
+ return svld1(pg, base);
+}
+
+svfloat32_t test_svld1_f32(svbool_t pg, const float32_t *base)
+{
+ // CHECK-LABEL: test_svld1_f32
+ // 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)
+ return svld1(pg, base);
+}
+
+svfloat64_t test_svld1_f64(svbool_t pg, const float64_t *base)
+{
+ // CHECK-LABEL: test_svld1_f64
+ // 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)
+ return svld1(pg, base);
+}
diff --git a/clang/utils/TableGen/SveEmitter.cpp b/clang/utils/TableGen/SveEmitter.cpp
index 8b53e376cb0d..e02e94dd98ae 100644
--- a/clang/utils/TableGen/SveEmitter.cpp
+++ b/clang/utils/TableGen/SveEmitter.cpp
@@ -100,6 +100,10 @@ class SVEType {
/// string for passing to the BUILTIN() macro in Builtins.def.
std::string builtin_str() const;
+ /// Return the C/C++ string representation of a type for use in the
+ /// arm_sve.h header file.
+ std::string str() const;
+
private:
/// Creates the type based on the typespec string in TS.
void applyTypespec();
@@ -335,6 +339,45 @@ std::string SVEType::builtin_str() const {
return "q" + utostr(getNumElements() * NumVectors) + S;
}
+std::string SVEType::str() const {
+ if (isPredicatePattern())
+ return "sv_pattern";
+
+ if (isPrefetchOp())
+ return "sv_prfop";
+
+ std::string S;
+ if (Void)
+ S += "void";
+ else {
+ if (isScalableVector())
+ S += "sv";
+ if (!Signed && !Float)
+ S += "u";
+
+ if (Float)
+ S += "float";
+ else if (isScalarPredicate())
+ S += "bool";
+ else
+ S += "int";
+
+ if (!isScalarPredicate())
+ S += utostr(ElementBitwidth);
+ if (!isScalableVector() && isVector())
+ S += "x" + utostr(getNumElements());
+ if (NumVectors > 1)
+ S += "x" + utostr(NumVectors);
+ S += "_t";
+ }
+
+ if (Constant)
+ S += " const";
+ if (Pointer)
+ S += " *";
+
+ return S;
+}
void SVEType::applyTypespec() {
for (char I : TS) {
switch (I) {
@@ -515,8 +558,19 @@ void Intrinsic::emitIntrinsic(raw_ostream &OS) const {
<< "(...) __builtin_sve_" << mangleName(ClassS)
<< "(__VA_ARGS__)\n";
} else {
- llvm_unreachable("Not yet implemented. Overloaded intrinsics will follow "
- "in a future patch");
+ std::string FullName = mangleName(ClassS);
+ std::string ProtoName = mangleName(ClassG);
+
+ OS << "__aio __attribute__((__clang_arm_builtin_alias("
+ << "__builtin_sve_" << FullName << ")))\n";
+
+ OS << getTypes()[0].str() << " " << ProtoName << "(";
+ for (unsigned I = 0; I < getTypes().size() - 1; ++I) {
+ if (I != 0)
+ OS << ", ";
+ OS << getTypes()[I + 1].str();
+ }
+ OS << ");\n";
}
}
@@ -559,6 +613,11 @@ void SVEEmitter::createIntrinsic(
Out.push_back(std::make_unique<Intrinsic>(Name, Proto, Merge,
LLVMName, Flags, TS, ClassS,
*this, Guard));
+
+ // Also generate the short-form (e.g. svadd_m) for the given type-spec.
+ if (Intrinsic::isOverloadedIntrinsic(Name))
+ Out.push_back(std::make_unique<Intrinsic>(
+ Name, Proto, Merge, LLVMName, Flags, TS, ClassG, *this, Guard));
}
}
@@ -608,6 +667,10 @@ void SVEEmitter::createHeader(raw_ostream &OS) {
OS << "typedef __SVFloat64_t svfloat64_t;\n";
OS << "typedef __SVBool_t svbool_t;\n\n";
+ OS << "/* Function attributes */\n";
+ OS << "#define __aio static inline __attribute__((__always_inline__, "
+ "__nodebug__, __overloadable__))\n\n";
+
SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
for (auto *R : RV)
More information about the cfe-commits
mailing list