diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -359,6 +359,8 @@ let Arches = arches; } def TargetARM : TargetArch<["arm", "thumb", "armeb", "thumbeb"]>; +def TargetAArch64 : TargetArch<["aarch64"]>; +def TargetAnyArm : TargetArch; def TargetAVR : TargetArch<["avr"]>; def TargetBPF : TargetArch<["bpfel", "bpfeb"]>; def TargetMips32 : TargetArch<["mips", "mipsel"]>; @@ -623,7 +625,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>; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -4980,6 +4980,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) @@ -4991,8 +5002,10 @@ unsigned BuiltinID = Ident->getBuiltinID(); StringRef AliasName = cast(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 --- /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 +// +// 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); +} diff --git a/clang/utils/TableGen/SveEmitter.cpp b/clang/utils/TableGen/SveEmitter.cpp --- a/clang/utils/TableGen/SveEmitter.cpp +++ b/clang/utils/TableGen/SveEmitter.cpp @@ -100,6 +100,10 @@ /// 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 @@ 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 @@ << "(...) __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 @@ Out.push_back(std::make_unique(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( + Name, Proto, Merge, LLVMName, Flags, TS, ClassG, *this, Guard)); } } @@ -608,6 +667,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)