From 5087ace65197471c07b78d16e3d599187c442cbf Mon Sep 17 00:00:00 2001 From: Sander de Smalen Date: Sun, 15 Mar 2020 14:29:45 +0000 Subject: [PATCH] [Clang][SVE] Parse builtin type string for scalable vectors This patch adds 'q' to mean 'scalable vector' in the builtin type string, and for SVE will return the matching builtin type as defined in the C/C++ language extensions for SVE. This patch also adds some scaffolding to generate the arm_sve.h header file, and some builtin definitions (+CodeGen) to be able to implement some simple masked load intrinsics that use the ACLE types, such as: svint8_t test_svld1_s8(svbool_t pg, const int8_t *base) { return svld1_s8(pg, base); } Reviewers: efriedma, rjmccall, rovka, rsandifo-arm, rengolin Reviewed By: efriedma Tags: #clang Differential Revision: https://reviews.llvm.org/D75298 --- clang/include/clang/AST/ASTContext.h | 6 + .../clang/Basic/AArch64SVEACLETypes.def | 28 ++-- clang/include/clang/Basic/Builtins.def | 1 + clang/include/clang/Basic/BuiltinsAArch64.def | 13 ++ clang/include/clang/Basic/arm_sve.td | 14 ++ clang/lib/AST/ASTContext.cpp | 55 ++++++-- clang/lib/CodeGen/CGBuiltin.cpp | 73 ++++++++++ clang/lib/CodeGen/CodeGenFunction.cpp | 10 +- clang/lib/CodeGen/CodeGenFunction.h | 5 + clang/lib/Headers/CMakeLists.txt | 2 + clang/lib/Headers/module.modulemap | 6 + .../aarch64-sve-intrinsics/acle_sve_ld1.c | 83 ++++++++++++ clang/utils/TableGen/CMakeLists.txt | 1 + clang/utils/TableGen/SveEmitter.cpp | 128 ++++++++++++++++++ clang/utils/TableGen/TableGen.cpp | 6 + clang/utils/TableGen/TableGenBackends.h | 2 + 16 files changed, 405 insertions(+), 28 deletions(-) create mode 100644 clang/include/clang/Basic/arm_sve.td create mode 100644 clang/test/CodeGen/aarch64-sve-intrinsics/acle_sve_ld1.c create mode 100644 clang/utils/TableGen/SveEmitter.cpp diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 75ab911d24597..d74edb8a8adb8 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1275,6 +1275,12 @@ class ASTContext : public RefCountedBase { /// Returns a vla type where known sizes are replaced with [*]. QualType getVariableArrayDecayedType(QualType Ty) const; + /// Return the unique reference to a scalable vector type of the specified + /// element type and scalable number of elements. + /// + /// \pre \p EltTy must be a built-in type. + QualType getScalableVectorType(QualType EltTy, unsigned NumElts) const; + /// Return the unique reference to a vector type of the specified /// element type and size. /// diff --git a/clang/include/clang/Basic/AArch64SVEACLETypes.def b/clang/include/clang/Basic/AArch64SVEACLETypes.def index 7d387587dc297..afa651841861c 100644 --- a/clang/include/clang/Basic/AArch64SVEACLETypes.def +++ b/clang/include/clang/Basic/AArch64SVEACLETypes.def @@ -38,32 +38,32 @@ //===----------------------------------------------------------------------===// #ifndef SVE_VECTOR_TYPE -#define SVE_VECTOR_TYPE(Name, Id, SingletonId, ElKind, ElBits, IsSigned, IsFP)\ +#define SVE_VECTOR_TYPE(Name, Id, SingletonId, NumEls, ElBits, IsSigned, IsFP) \ SVE_TYPE(Name, Id, SingletonId) #endif #ifndef SVE_PREDICATE_TYPE -#define SVE_PREDICATE_TYPE(Name, Id, SingletonId, ElKind)\ +#define SVE_PREDICATE_TYPE(Name, Id, SingletonId, NumEls)\ SVE_TYPE(Name, Id, SingletonId) #endif //===- Vector point types -----------------------------------------------===// -SVE_VECTOR_TYPE("__SVInt8_t", SveInt8, SveInt8Ty, SveElSInt8, 8, true, false) -SVE_VECTOR_TYPE("__SVInt16_t", SveInt16, SveInt16Ty, SveElSInt16, 16, true, false) -SVE_VECTOR_TYPE("__SVInt32_t", SveInt32, SveInt32Ty, SveElSInt32, 32, true, false) -SVE_VECTOR_TYPE("__SVInt64_t", SveInt64, SveInt64Ty, SveElSInt64, 64, true, false) +SVE_VECTOR_TYPE("__SVInt8_t", SveInt8, SveInt8Ty, 16, 8, true, false) +SVE_VECTOR_TYPE("__SVInt16_t", SveInt16, SveInt16Ty, 8, 16, true, false) +SVE_VECTOR_TYPE("__SVInt32_t", SveInt32, SveInt32Ty, 4, 32, true, false) +SVE_VECTOR_TYPE("__SVInt64_t", SveInt64, SveInt64Ty, 2, 64, true, false) -SVE_VECTOR_TYPE("__SVUint8_t", SveUint8, SveUint8Ty, SveElUInt8, 8, false, false) -SVE_VECTOR_TYPE("__SVUint16_t", SveUint16, SveUint16Ty, SveElUInt16, 16, false, false) -SVE_VECTOR_TYPE("__SVUint32_t", SveUint32, SveUint32Ty, SveElUInt32, 32, false, false) -SVE_VECTOR_TYPE("__SVUint64_t", SveUint64, SveUint64Ty, SveElUInt64, 64, false, false) +SVE_VECTOR_TYPE("__SVUint8_t", SveUint8, SveUint8Ty, 16, 8, false, false) +SVE_VECTOR_TYPE("__SVUint16_t", SveUint16, SveUint16Ty, 8, 16, false, false) +SVE_VECTOR_TYPE("__SVUint32_t", SveUint32, SveUint32Ty, 4, 32, false, false) +SVE_VECTOR_TYPE("__SVUint64_t", SveUint64, SveUint64Ty, 2, 64, false, false) -SVE_VECTOR_TYPE("__SVFloat16_t", SveFloat16, SveFloat16Ty, SveElHalf, 16, true, true) -SVE_VECTOR_TYPE("__SVFloat32_t", SveFloat32, SveFloat32Ty, SveElFloat, 32, true, true) -SVE_VECTOR_TYPE("__SVFloat64_t", SveFloat64, SveFloat64Ty, SveElDouble, 64, true, true) +SVE_VECTOR_TYPE("__SVFloat16_t", SveFloat16, SveFloat16Ty, 8, 16, true, true) +SVE_VECTOR_TYPE("__SVFloat32_t", SveFloat32, SveFloat32Ty, 4, 32, true, true) +SVE_VECTOR_TYPE("__SVFloat64_t", SveFloat64, SveFloat64Ty, 2, 64, true, true) -SVE_PREDICATE_TYPE("__SVBool_t", SveBool, SveBoolTy, SveElBool) +SVE_PREDICATE_TYPE("__SVBool_t", SveBool, SveBoolTy, 16) #undef SVE_VECTOR_TYPE #undef SVE_PREDICATE_TYPE diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def index 9a68f72da6d9b..85f775a7cad8b 100644 --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -36,6 +36,7 @@ // a -> __builtin_va_list // A -> "reference" to __builtin_va_list // V -> Vector, followed by the number of elements and the base type. +// q -> Scalable vector, followed by the number of elements and the base type. // E -> ext_vector, followed by the number of elements and the base type. // X -> _Complex, followed by the base type. // Y -> ptrdiff_t diff --git a/clang/include/clang/Basic/BuiltinsAArch64.def b/clang/include/clang/Basic/BuiltinsAArch64.def index f07c567053dea..8f3a24c2e1f65 100644 --- a/clang/include/clang/Basic/BuiltinsAArch64.def +++ b/clang/include/clang/Basic/BuiltinsAArch64.def @@ -99,6 +99,19 @@ BUILTIN(__builtin_arm_tcommit, "v", "n") BUILTIN(__builtin_arm_tcancel, "vWUIi", "n") BUILTIN(__builtin_arm_ttest, "WUi", "nc") +// SVE +BUILTIN(__builtin_sve_svld1_s16, "q8sq16bSsC*", "n") +BUILTIN(__builtin_sve_svld1_s32, "q4iq16bSiC*", "n") +BUILTIN(__builtin_sve_svld1_s64, "q2Wiq16bSWiC*", "n") +BUILTIN(__builtin_sve_svld1_s8, "q16Scq16bScC*", "n") +BUILTIN(__builtin_sve_svld1_u16, "q8Usq16bUsC*", "n") +BUILTIN(__builtin_sve_svld1_u32, "q4Uiq16bUiC*", "n") +BUILTIN(__builtin_sve_svld1_u64, "q2UWiq16bUWiC*", "n") +BUILTIN(__builtin_sve_svld1_u8, "q16Ucq16bUcC*", "n") +BUILTIN(__builtin_sve_svld1_f64, "q2dq16bdC*", "n") +BUILTIN(__builtin_sve_svld1_f32, "q4fq16bfC*", "n") +BUILTIN(__builtin_sve_svld1_f16, "q8hq16bhC*", "n") + TARGET_HEADER_BUILTIN(_BitScanForward, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_BitScanReverse, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_BitScanForward64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") diff --git a/clang/include/clang/Basic/arm_sve.td b/clang/include/clang/Basic/arm_sve.td new file mode 100644 index 0000000000000..10417cdfcdea1 --- /dev/null +++ b/clang/include/clang/Basic/arm_sve.td @@ -0,0 +1,14 @@ +//===--- arm_sve.td - ARM SVE compiler interface ------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the TableGen definitions from which the ARM SVE header +// file will be generated. See: +// +// https://developer.arm.com/architectures/system-architectures/software-standards/acle +// +//===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 436880968b1f8..77d5e59d9f0cc 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2100,16 +2100,16 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { // Because the length is only known at runtime, we use a dummy value // of 0 for the static length. The alignment values are those defined // by the Procedure Call Standard for the Arm Architecture. -#define SVE_VECTOR_TYPE(Name, Id, SingletonId, ElKind, ElBits, IsSigned, IsFP)\ - case BuiltinType::Id: \ - Width = 0; \ - Align = 128; \ - break; -#define SVE_PREDICATE_TYPE(Name, Id, SingletonId, ElKind) \ - case BuiltinType::Id: \ - Width = 0; \ - Align = 16; \ - break; +#define SVE_VECTOR_TYPE(Name, Id, SingletonId, NumEls, ElBits, IsSigned, IsFP) \ + case BuiltinType::Id: \ + Width = 0; \ + Align = 128; \ + break; +#define SVE_PREDICATE_TYPE(Name, Id, SingletonId, NumEls) \ + case BuiltinType::Id: \ + Width = 0; \ + Align = 16; \ + break; #include "clang/Basic/AArch64SVEACLETypes.def" } break; @@ -3584,6 +3584,28 @@ QualType ASTContext::getIncompleteArrayType(QualType elementType, return QualType(newType, 0); } +/// getScalableVectorType - Return the unique reference to a scalable vector +/// type of the specified element type and size. VectorType must be a built-in +/// type. +QualType ASTContext::getScalableVectorType(QualType EltTy, + unsigned NumElts) const { + if (Target->hasAArch64SVETypes()) { + uint64_t EltTySize = getTypeSize(EltTy); +#define SVE_VECTOR_TYPE(Name, Id, SingletonId, NumEls, ElBits, IsSigned, IsFP) \ + if (!EltTy->isBooleanType() && \ + ((EltTy->hasIntegerRepresentation() && \ + EltTy->hasSignedIntegerRepresentation() == IsSigned) || \ + (EltTy->hasFloatingRepresentation() && IsFP)) && \ + EltTySize == ElBits && NumElts == NumEls) \ + return SingletonId; +#define SVE_PREDICATE_TYPE(Name, Id, SingletonId, NumEls) \ + if (EltTy->isBooleanType() && NumElts == NumEls) \ + return SingletonId; +#include "clang/Basic/AArch64SVEACLETypes.def" + } + return QualType(); +} + /// getVectorType - Return the unique reference to a vector type of /// the specified element type and size. VectorType must be a built-in type. QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts, @@ -9699,6 +9721,19 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, else Type = Context.getLValueReferenceType(Type); break; + case 'q': { + char *End; + unsigned NumElements = strtoul(Str, &End, 10); + assert(End != Str && "Missing vector size"); + Str = End; + + QualType ElementType = DecodeTypeFromStr(Str, Context, Error, + RequiresICE, false); + assert(!RequiresICE && "Can't require vector ICE"); + + Type = Context.getScalableVectorType(ElementType, NumElements); + break; + } case 'V': { char *End; unsigned NumElements = strtoul(Str, &End, 10); diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 436084ef23cb9..d333aeffefd9e 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -7384,6 +7384,58 @@ Value *CodeGenFunction::vectorWrapScalar16(Value *Op) { return Op; } +// Reinterpret the input predicate so that it can be used to correctly isolate +// the elements of the specified datatype. +Value *CodeGenFunction::EmitSVEPredicateCast(Value *Pred, + llvm::VectorType *VTy) { + llvm::VectorType *RTy = llvm::VectorType::get( + IntegerType::get(getLLVMContext(), 1), VTy->getElementCount()); + if (Pred->getType() == RTy) + return Pred; + + unsigned IntID; + llvm::Type *IntrinsicTy; + switch (VTy->getNumElements()) { + default: + llvm_unreachable("unsupported element count!"); + case 2: + case 4: + case 8: + IntID = Intrinsic::aarch64_sve_convert_from_svbool; + IntrinsicTy = RTy; + break; + case 16: + IntID = Intrinsic::aarch64_sve_convert_to_svbool; + IntrinsicTy = Pred->getType(); + break; + } + + Function *F = CGM.getIntrinsic(IntID, IntrinsicTy); + Value *C = Builder.CreateCall(F, Pred); + assert(C->getType() == RTy && "Unexpected return type!"); + return C; +} + +Value *CodeGenFunction::EmitSVEMaskedLoad(llvm::Type *ReturnTy, + SmallVectorImpl &Ops) { + llvm::PointerType *PTy = cast(Ops[1]->getType()); + llvm::Type *MemEltTy = PTy->getPointerElementType(); + + // The vector type that is returned may be different from the + // eventual type loaded from memory. + auto VectorTy = cast(ReturnTy); + auto MemoryTy = + llvm::VectorType::get(MemEltTy, VectorTy->getVectorElementCount()); + + Value *Offset = Builder.getInt32(0); + Value *Predicate = EmitSVEPredicateCast(Ops[0], MemoryTy); + Value *BasePtr = Builder.CreateBitCast(Ops[1], MemoryTy->getPointerTo()); + BasePtr = Builder.CreateGEP(MemoryTy, BasePtr, Offset); + + Value *Splat0 = Constant::getNullValue(MemoryTy); + return Builder.CreateMaskedLoad(BasePtr, Align(1), Predicate, Splat0); +} + Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, const CallExpr *E, llvm::Triple::ArchType Arch) { @@ -7420,6 +7472,27 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, return Builder.CreateCall(F, llvm::ConstantInt::get(Int32Ty, HintID)); } + switch (BuiltinID) { + case AArch64::BI__builtin_sve_svld1_u8: + case AArch64::BI__builtin_sve_svld1_u16: + case AArch64::BI__builtin_sve_svld1_u32: + case AArch64::BI__builtin_sve_svld1_u64: + case AArch64::BI__builtin_sve_svld1_s8: + case AArch64::BI__builtin_sve_svld1_s16: + case AArch64::BI__builtin_sve_svld1_s32: + case AArch64::BI__builtin_sve_svld1_s64: + case AArch64::BI__builtin_sve_svld1_f16: + case AArch64::BI__builtin_sve_svld1_f32: + case AArch64::BI__builtin_sve_svld1_f64: { + llvm::SmallVector Ops = {EmitScalarExpr(E->getArg(0)), + EmitScalarExpr(E->getArg(1))}; + llvm::Type *Ty = ConvertType(E->getType()); + return EmitSVEMaskedLoad(Ty, Ops); + } + default: + break; + } + if (BuiltinID == AArch64::BI__builtin_arm_prefetch) { Value *Address = EmitScalarExpr(E->getArg(0)); Value *RW = EmitScalarExpr(E->getArg(1)); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index d6c2afc51b04c..3393b1b3c5fbf 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -495,13 +495,15 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { // Scan function arguments for vector width. for (llvm::Argument &A : CurFn->args()) if (auto *VT = dyn_cast(A.getType())) - LargestVectorWidth = std::max((uint64_t)LargestVectorWidth, - VT->getPrimitiveSizeInBits().getFixedSize()); + LargestVectorWidth = + std::max((uint64_t)LargestVectorWidth, + VT->getPrimitiveSizeInBits().getKnownMinSize()); // Update vector width based on return type. if (auto *VT = dyn_cast(CurFn->getReturnType())) - LargestVectorWidth = std::max((uint64_t)LargestVectorWidth, - VT->getPrimitiveSizeInBits().getFixedSize()); + LargestVectorWidth = + std::max((uint64_t)LargestVectorWidth, + VT->getPrimitiveSizeInBits().getKnownMinSize()); // Add the required-vector-width attribute. This contains the max width from: // 1. min-vector-width attribute used in the source program. diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index f82e489e6217f..e470becbe4262 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3900,6 +3900,11 @@ class CodeGenFunction : public CodeGenTypeCache { llvm::Value *EmitNeonRShiftImm(llvm::Value *Vec, llvm::Value *Amt, llvm::Type *Ty, bool usgn, const char *name); llvm::Value *vectorWrapScalar16(llvm::Value *Op); + + llvm::Value *EmitSVEPredicateCast(llvm::Value *Pred, llvm::VectorType *VTy); + llvm::Value *EmitSVEMaskedLoad(llvm::Type *ReturnTy, + SmallVectorImpl &Ops); + llvm::Value *EmitAArch64BuiltinExpr(unsigned BuiltinID, const CallExpr *E, llvm::Triple::ArchType Arch); llvm::Value *EmitBPFBuiltinExpr(unsigned BuiltinID, const CallExpr *E); diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt index 923784305d05a..28d43cb7ed35a 100644 --- a/clang/lib/Headers/CMakeLists.txt +++ b/clang/lib/Headers/CMakeLists.txt @@ -184,6 +184,8 @@ endforeach( f ) clang_generate_header(-gen-arm-neon arm_neon.td arm_neon.h) # Generate arm_fp16.h clang_generate_header(-gen-arm-fp16 arm_fp16.td arm_fp16.h) +# Generate arm_sve.h +clang_generate_header(-gen-arm-sve-header arm_sve.td arm_sve.h) # Generate arm_mve.h clang_generate_header(-gen-arm-mve-header arm_mve.td arm_mve.h) # Generate arm_cde.h diff --git a/clang/lib/Headers/module.modulemap b/clang/lib/Headers/module.modulemap index 7954a77a41258..6894672ef0529 100644 --- a/clang/lib/Headers/module.modulemap +++ b/clang/lib/Headers/module.modulemap @@ -27,6 +27,12 @@ module _Builtin_intrinsics [system] [extern_c] { header "arm_fp16.h" export * } + + explicit module sve { + requires sve + header "arm_sve.h" + export * + } } explicit module intel { diff --git a/clang/test/CodeGen/aarch64-sve-intrinsics/acle_sve_ld1.c b/clang/test/CodeGen/aarch64-sve-intrinsics/acle_sve_ld1.c new file mode 100644 index 0000000000000..82f66432fe332 --- /dev/null +++ b/clang/test/CodeGen/aarch64-sve-intrinsics/acle_sve_ld1.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_s8(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_s16(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_s32(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_s64(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_u8(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_u16(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_u32(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_u64(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_f16(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_f32(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_f64(pg, base); +} diff --git a/clang/utils/TableGen/CMakeLists.txt b/clang/utils/TableGen/CMakeLists.txt index 7deca9971090b..41f15e2d79091 100644 --- a/clang/utils/TableGen/CMakeLists.txt +++ b/clang/utils/TableGen/CMakeLists.txt @@ -17,6 +17,7 @@ add_tablegen(clang-tblgen CLANG ClangTypeNodesEmitter.cpp MveEmitter.cpp NeonEmitter.cpp + SveEmitter.cpp TableGen.cpp ) set_target_properties(clang-tblgen PROPERTIES FOLDER "Clang tablegenning") diff --git a/clang/utils/TableGen/SveEmitter.cpp b/clang/utils/TableGen/SveEmitter.cpp new file mode 100644 index 0000000000000..3c9f917d0ffb0 --- /dev/null +++ b/clang/utils/TableGen/SveEmitter.cpp @@ -0,0 +1,128 @@ +//===- SveEmitter.cpp - Generate arm_sve.h for use with clang -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend is responsible for emitting arm_sve.h, which includes +// a declaration and definition of each function specified by the ARM C/C++ +// Language Extensions (ACLE). +// +// For details, visit: +// https://developer.arm.com/architectures/system-architectures/software-standards/acle +// +// Each SVE instruction is implemented in terms of 1 or more functions which +// are suffixed with the element type of the input vectors. Functions may be +// implemented in terms of generic vector operations such as +, *, -, etc. or +// by calling a __builtin_-prefixed function which will be handled by clang's +// CodeGen library. +// +// See also the documentation in include/clang/Basic/arm_sve.td. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/Error.h" +#include +#include +#include +#include + +using namespace llvm; + +//===----------------------------------------------------------------------===// +// SVEEmitter +//===----------------------------------------------------------------------===// + +namespace { + +class SVEEmitter { +private: + RecordKeeper &Records; + +public: + SVEEmitter(RecordKeeper &R) : Records(R) {} + + // run - Emit arm_sve.h + void run(raw_ostream &o); +}; + +} // end anonymous namespace + + +//===----------------------------------------------------------------------===// +// SVEEmitter implementation +//===----------------------------------------------------------------------===// + +void SVEEmitter::run(raw_ostream &OS) { + OS << "/*===---- arm_sve.h - ARM SVE intrinsics " + "-----------------------------------===\n" + " *\n" + " *\n" + " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " + "Exceptions.\n" + " * See https://llvm.org/LICENSE.txt for license information.\n" + " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" + " *\n" + " *===-----------------------------------------------------------------" + "------===\n" + " */\n\n"; + + OS << "#ifndef __ARM_SVE_H\n"; + OS << "#define __ARM_SVE_H\n\n"; + + OS << "#if !defined(__ARM_FEATURE_SVE)\n"; + OS << "#error \"SVE support not enabled\"\n"; + OS << "#else\n\n"; + + OS << "#include \n\n"; + OS << "#ifndef __cplusplus\n"; + OS << "#include \n"; + OS << "#endif\n\n"; + + OS << "typedef __fp16 float16_t;\n"; + OS << "typedef float float32_t;\n"; + OS << "typedef double float64_t;\n"; + OS << "typedef bool bool_t;\n\n"; + + OS << "typedef __SVInt8_t svint8_t;\n"; + OS << "typedef __SVInt16_t svint16_t;\n"; + OS << "typedef __SVInt32_t svint32_t;\n"; + OS << "typedef __SVInt64_t svint64_t;\n"; + OS << "typedef __SVUint8_t svuint8_t;\n"; + OS << "typedef __SVUint16_t svuint16_t;\n"; + OS << "typedef __SVUint32_t svuint32_t;\n"; + OS << "typedef __SVUint64_t svuint64_t;\n"; + OS << "typedef __SVFloat16_t svfloat16_t;\n"; + OS << "typedef __SVFloat32_t svfloat32_t;\n"; + OS << "typedef __SVFloat64_t svfloat64_t;\n"; + OS << "typedef __SVBool_t svbool_t;\n\n"; + + OS << "#define svld1_u8(...) __builtin_sve_svld1_u8(__VA_ARGS__)\n"; + OS << "#define svld1_u16(...) __builtin_sve_svld1_u16(__VA_ARGS__)\n"; + OS << "#define svld1_u32(...) __builtin_sve_svld1_u32(__VA_ARGS__)\n"; + OS << "#define svld1_u64(...) __builtin_sve_svld1_u64(__VA_ARGS__)\n"; + OS << "#define svld1_s8(...) __builtin_sve_svld1_s8(__VA_ARGS__)\n"; + OS << "#define svld1_s16(...) __builtin_sve_svld1_s16(__VA_ARGS__)\n"; + OS << "#define svld1_s32(...) __builtin_sve_svld1_s32(__VA_ARGS__)\n"; + OS << "#define svld1_s64(...) __builtin_sve_svld1_s64(__VA_ARGS__)\n"; + OS << "#define svld1_f16(...) __builtin_sve_svld1_f16(__VA_ARGS__)\n"; + OS << "#define svld1_f32(...) __builtin_sve_svld1_f32(__VA_ARGS__)\n"; + OS << "#define svld1_f64(...) __builtin_sve_svld1_f64(__VA_ARGS__)\n"; + + OS << "#endif /*__ARM_FEATURE_SVE */\n"; + OS << "#endif /* __ARM_SVE_H */\n"; +} + +namespace clang { +void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) { + SVEEmitter(Records).run(OS); +} + +} // End namespace clang diff --git a/clang/utils/TableGen/TableGen.cpp b/clang/utils/TableGen/TableGen.cpp index 3d8f6dc352d01..b0f9120416bc2 100644 --- a/clang/utils/TableGen/TableGen.cpp +++ b/clang/utils/TableGen/TableGen.cpp @@ -70,6 +70,7 @@ enum ActionType { GenArmMveBuiltinSema, GenArmMveBuiltinCG, GenArmMveBuiltinAliases, + GenArmSveHeader, GenArmCdeHeader, GenArmCdeBuiltinDef, GenArmCdeBuiltinSema, @@ -185,6 +186,8 @@ cl::opt Action( "Generate ARM NEON sema support for clang"), clEnumValN(GenArmNeonTest, "gen-arm-neon-test", "Generate ARM NEON tests for clang"), + clEnumValN(GenArmSveHeader, "gen-arm-sve-header", + "Generate arm_sve.h for clang"), clEnumValN(GenArmMveHeader, "gen-arm-mve-header", "Generate arm_mve.h for clang"), clEnumValN(GenArmMveBuiltinDef, "gen-arm-mve-builtin-def", @@ -366,6 +369,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenArmMveBuiltinAliases: EmitMveBuiltinAliases(Records, OS); break; + case GenArmSveHeader: + EmitSveHeader(Records, OS); + break; case GenArmCdeHeader: EmitCdeHeader(Records, OS); break; diff --git a/clang/utils/TableGen/TableGenBackends.h b/clang/utils/TableGen/TableGenBackends.h index cc300319c1006..3ff6b26c40526 100644 --- a/clang/utils/TableGen/TableGenBackends.h +++ b/clang/utils/TableGen/TableGenBackends.h @@ -91,6 +91,8 @@ void EmitNeon2(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); void EmitNeonSema2(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); void EmitNeonTest2(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); +void EmitSveHeader(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); + void EmitMveHeader(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); void EmitMveBuiltinDef(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); void EmitMveBuiltinSema(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);