Index: clang/include/clang/AST/Type.h =================================================================== --- clang/include/clang/AST/Type.h +++ clang/include/clang/AST/Type.h @@ -1981,6 +1981,9 @@ bool isSizelessType() const; bool isSizelessBuiltinType() const; + /// Returns true for SVE scalable vector types. + bool isSVESizelessBuiltinType() const; + /// Determines if this is a sizeless type supported by the /// 'arm_sve_vector_bits' type attribute, which can be applied to a single /// SVE vector or predicate, excluding tuple types such as svint32x4_t. Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3030,6 +3030,8 @@ def err_attribute_arm_feature_sve_bits_unsupported : Error< "%0 is only supported when '-msve-vector-bits=' is specified with a " "value of 128, 256, 512, 1024 or 2048.">; +def err_sve_vector_in_non_sve_target : Error< + "SVE vector type %0 cannot be used in a target without sve">; def err_attribute_requires_positive_integer : Error< "%0 attribute requires a %select{positive|non-negative}1 " "integral compile time constant expression">; Index: clang/lib/AST/Type.cpp =================================================================== --- clang/lib/AST/Type.cpp +++ clang/lib/AST/Type.cpp @@ -2320,6 +2320,20 @@ bool Type::isSizelessType() const { return isSizelessBuiltinType(); } +bool Type::isSVESizelessBuiltinType() const { + if (const BuiltinType *BT = getAs()) { + switch (BT->getKind()) { + // SVE Types +#define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id: +#include "clang/Basic/AArch64SVEACLETypes.def" + return true; + default: + return false; + } + } + return false; +} + bool Type::isVLSTBuiltinType() const { if (const BuiltinType *BT = getAs()) { switch (BT->getKind()) { Index: clang/lib/Basic/Targets/AArch64.h =================================================================== --- clang/lib/Basic/Targets/AArch64.h +++ clang/lib/Basic/Targets/AArch64.h @@ -115,6 +115,8 @@ bool hasFeature(StringRef Feature) const override; bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override; + void setFeatureEnabled(llvm::StringMap &Features, StringRef Name, + bool Enabled) const override; bool hasBFloat16Type() const override; Index: clang/lib/Basic/Targets/AArch64.cpp =================================================================== --- clang/lib/Basic/Targets/AArch64.cpp +++ clang/lib/Basic/Targets/AArch64.cpp @@ -670,6 +670,26 @@ return true; } +void AArch64TargetInfo::setFeatureEnabled(llvm::StringMap &Features, + StringRef Name, bool Enabled) const { + Features[Name] = Enabled; + + if (Name == "sve2" && Enabled) + setFeatureEnabled(Features, "sve", true); + else if ((Name == "sve2-bitperm" || Name == "sve2-sha3" || + Name == "sve2-aes" || Name == "sve2-sm4") && + Enabled) + setFeatureEnabled(Features, "sve2", true); + else if (Name == "sve" && !Enabled) + setFeatureEnabled(Features, "sve2", false); + else if (Name == "sve2" && !Enabled) { + setFeatureEnabled(Features, "sve2-bitperm", false); + setFeatureEnabled(Features, "sve2-sha3", false); + setFeatureEnabled(Features, "sve2-aes", false); + setFeatureEnabled(Features, "sve2-sm4", false); + } +} + bool AArch64TargetInfo::hasBFloat16Type() const { return true; } Index: clang/lib/Sema/Sema.cpp =================================================================== --- clang/lib/Sema/Sema.cpp +++ clang/lib/Sema/Sema.cpp @@ -2006,6 +2006,15 @@ if (D) targetDiag(D->getLocation(), diag::note_defined_here, FD) << D; } + + // Don't allow SVE types in functions without a SVE target. + if (Ty->isSVESizelessBuiltinType() && FD && FD->hasBody()) { + llvm::StringMap CallerFeatureMap; + Context.getFunctionFeatureMap(CallerFeatureMap, FD); + if (!Builtin::evaluateRequiredTargetFeatures( + "sve", CallerFeatureMap)) + Diag(D->getLocation(), diag::err_sve_vector_in_non_sve_target) << Ty; + } }; CheckType(Ty); Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -8575,6 +8575,19 @@ NewVD->setInvalidDecl(); return; } + + // Check that SVE types are only used in functions with SVE available. + if (T->isSVESizelessBuiltinType() && CurContext->isFunctionOrMethod()) { + const FunctionDecl *FD = cast(CurContext); + llvm::StringMap CallerFeatureMap; + Context.getFunctionFeatureMap(CallerFeatureMap, FD); + if (!Builtin::evaluateRequiredTargetFeatures( + "sve", CallerFeatureMap)) { + Diag(NewVD->getLocation(), diag::err_sve_vector_in_non_sve_target) << T; + NewVD->setInvalidDecl(); + return; + } + } } /// Perform semantic checking on a newly-created variable Index: clang/test/Sema/arm-sve-target.cpp =================================================================== --- /dev/null +++ clang/test/Sema/arm-sve-target.cpp @@ -0,0 +1,60 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -DNONEON -std=c++11 -triple aarch64-arm-none-eabi -target-feature -sve %s + +// A target without sve should not be able to use sve types. + +void test_var() { + __SVFloat32_t x; // expected-error {{SVE vector type '__SVFloat32_t' cannot be used in a target without sve}} +} + +__attribute__((target("sve"))) +void test_var_target() { + __SVFloat32_t x; +} + +__attribute__((target("sve2"))) +void test_var_target2() { + __SVFloat32_t x; +} + +__attribute__((target("sve2-bitperm"))) +void test_var_target3() { + __SVFloat32_t x; +} + +__SVFloat32_t other_ret(); +__SVFloat32_t test_ret() { // expected-error {{SVE vector type '__SVFloat32_t' cannot be used in a target without sve}} + return other_ret(); +} + +__attribute__((target("sve"))) +__SVFloat32_t test_ret_target() { + return other_ret(); +} + +void test_arg(__SVFloat32_t arg) { // expected-error {{SVE vector type '__SVFloat32_t' cannot be used in a target without sve}} +} + +__attribute__((target("sve"))) +void test_arg_target(__SVFloat32_t arg) { +} + +__clang_svint32x4_t test4x() { // expected-error {{SVE vector type '__clang_svint32x4_t' cannot be used in a target without sve}} + __clang_svint32x4_t x; // expected-error {{SVE vector type '__clang_svint32x4_t' cannot be used in a target without sve}} + return x; +} + +__attribute__((target("sve"))) +__clang_svint32x4_t test4x_target() { + __clang_svint32x4_t x; + return x; +} + +// Pointers are still valid to pass around. +void foo(__SVFloat32_t *&ptrA, __SVFloat32_t* &ptrB) { + ptrA = ptrB; +} + +__SVFloat32_t* foo(int x, __SVFloat32_t *ptrA) { + return ptrA; +} +