Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -358,6 +358,8 @@ let Arches = arches; } def TargetARM : TargetArch<["arm", "thumb", "armeb", "thumbeb"]>; +def TargetAArch64 : TargetArch<["aarch64"]>; +def TargetARM_AArch64 : TargetArch; def TargetAVR : TargetArch<["avr"]>; def TargetBPF : TargetArch<["bpfel", "bpfeb"]>; def TargetMips32 : TargetArch<["mips", "mipsel"]>; @@ -622,7 +624,7 @@ let Documentation = [Undocumented]; } -def ArmBuiltinAlias : InheritableAttr, TargetSpecificAttr { +def ArmBuiltinAlias : InheritableAttr, TargetSpecificAttr { let Spellings = [Clang<"__clang_arm_builtin_alias">]; let Args = [IdentifierArgument<"BuiltinName">]; let Subjects = SubjectList<[Function], ErrorDiag>; Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -4977,6 +4977,17 @@ 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) @@ -4989,7 +5000,8 @@ StringRef AliasName = cast(D)->getIdentifier()->getName(); if (!ArmMveAliasValid(BuiltinID, AliasName) && - !ArmCdeAliasValid(BuiltinID, AliasName)) { + !ArmCdeAliasValid(BuiltinID, AliasName) && + !ArmSveAliasValid(BuiltinID, AliasName)) { S.Diag(AL.getLoc(), diag::err_attribute_arm_builtin_alias); return; } Index: clang/test/CodeGen/aarch64-sve-intrinsics/acle_sve_ld1_shortform.c =================================================================== --- /dev/null +++ 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 +// +// ld1 +// + +svint8_t test_svld1_s8(svbool_t pg, const int8_t *base) +{ + // CHECK-LABEL: test_svld1_s8 + // CHECK: @llvm.masked.load.nxv16i8.p0nxv16i8(* %{{.*}}, i32 1, %{{.*}}, zeroinitializer) + return svld1(pg, base); +} + +svint16_t test_svld1_s16(svbool_t pg, const int16_t *base) +{ + // CHECK-LABEL: test_svld1_s16 + // CHECK: @llvm.masked.load.nxv8i16.p0nxv8i16(* %{{.*}}, i32 1, %{{.*}}, zeroinitializer) + return svld1(pg, base); +} + +svint32_t test_svld1_s32(svbool_t pg, const int32_t *base) +{ + // CHECK-LABEL: test_svld1_s32 + // CHECK: @llvm.masked.load.nxv4i32.p0nxv4i32(* %{{.*}}, i32 1, %{{.*}}, zeroinitializer) + return svld1(pg, base); +} + +svint64_t test_svld1_s64(svbool_t pg, const int64_t *base) +{ + // CHECK-LABEL: test_svld1_s64 + // CHECK: @llvm.masked.load.nxv2i64.p0nxv2i64(* %{{.*}}, i32 1, %{{.*}}, zeroinitializer) + return svld1(pg, base); +} + +svuint8_t test_svld1_u8(svbool_t pg, const uint8_t *base) +{ + // CHECK-LABEL: test_svld1_u8 + // CHECK: @llvm.masked.load.nxv16i8.p0nxv16i8(* %{{.*}}, i32 1, %{{.*}}, zeroinitializer) + return svld1(pg, base); +} + +svuint16_t test_svld1_u16(svbool_t pg, const uint16_t *base) +{ + // CHECK-LABEL: test_svld1_u16 + // CHECK: @llvm.masked.load.nxv8i16.p0nxv8i16(* %{{.*}}, i32 1, %{{.*}}, zeroinitializer) + return svld1(pg, base); +} + +svuint32_t test_svld1_u32(svbool_t pg, const uint32_t *base) +{ + // CHECK-LABEL: test_svld1_u32 + // CHECK: @llvm.masked.load.nxv4i32.p0nxv4i32(* %{{.*}}, i32 1, %{{.*}}, zeroinitializer) + return svld1(pg, base); +} + +svuint64_t test_svld1_u64(svbool_t pg, const uint64_t *base) +{ + // CHECK-LABEL: test_svld1_u64 + // CHECK: @llvm.masked.load.nxv2i64.p0nxv2i64(* %{{.*}}, i32 1, %{{.*}}, zeroinitializer) + return svld1(pg, base); +} + +svfloat16_t test_svld1_f16(svbool_t pg, const float16_t *base) +{ + // CHECK-LABEL: test_svld1_f16 + // CHECK: @llvm.masked.load.nxv8f16.p0nxv8f16(* %{{.*}}, i32 1, %{{.*}}, zeroinitializer) + return svld1(pg, base); +} + +svfloat32_t test_svld1_f32(svbool_t pg, const float32_t *base) +{ + // CHECK-LABEL: test_svld1_f32 + // CHECK: @llvm.masked.load.nxv4f32.p0nxv4f32(* %{{.*}}, i32 1, %{{.*}}, zeroinitializer) + return svld1(pg, base); +} + +svfloat64_t test_svld1_f64(svbool_t pg, const float64_t *base) +{ + // CHECK-LABEL: test_svld1_f64 + // CHECK: @llvm.masked.load.nxv2f64.p0nxv2f64(* %{{.*}}, i32 1, %{{.*}}, zeroinitializer) + return svld1(pg, base); +} Index: clang/utils/TableGen/SveEmitter.cpp =================================================================== --- clang/utils/TableGen/SveEmitter.cpp +++ clang/utils/TableGen/SveEmitter.cpp @@ -102,6 +102,8 @@ /// string for passing to the BUILTIN() macro in Builtins.def. std::string builtin_str() const; + std::string str() const; + private: /// Creates the type based on the typespec string in TS. void applyTypespec(); @@ -341,6 +343,45 @@ 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) { @@ -521,8 +562,19 @@ << "(...) __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"; } } @@ -565,6 +617,12 @@ Out.push_back(std::make_unique(R, Name, Proto, Merge, MemEltType, 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(R, Name, Proto, Merge, + MemEltType, LLVMName, Flags, TS, + ClassG, *this, Guard)); } } @@ -643,6 +701,10 @@ 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, 128> Defs; std::vector RV = Records.getAllDerivedDefinitions("Inst"); for (auto *R : RV)