[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