diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -2026,6 +2026,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. diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3048,6 +3048,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">; diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -2343,6 +2343,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()) { diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2035,6 +2035,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); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -8690,6 +8690,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 diff --git a/clang/test/CodeGen/aarch64-targetattr-arch.c b/clang/test/CodeGen/aarch64-targetattr-arch.c --- a/clang/test/CodeGen/aarch64-targetattr-arch.c +++ b/clang/test/CodeGen/aarch64-targetattr-arch.c @@ -22,14 +22,14 @@ return svadd_s8_z(pg, op1, op2); } -svint8_t test_errors(svbool_t pg, svint8_t op1, svint8_t op2) +void test_errors() { #ifdef HAS8 // expected-error@+2{{always_inline function '__crc32cd' requires target feature 'crc'}} #endif __crc32cd(1, 1); #if defined(HAS8) || defined(HAS81) -// expected-error@+2{{'svadd_s8_z' needs target feature sve}} +// expected-error@+2{{'svundef_s8' needs target feature sve}} #endif - return svadd_s8_z(pg, op1, op2); + svundef_s8(); } diff --git a/clang/test/Sema/arm-sve-target.cpp b/clang/test/Sema/arm-sve-target.cpp new file mode 100644 --- /dev/null +++ b/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 %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; +} +