diff --git a/clang/include/clang/Sema/SemaARM.h b/clang/include/clang/Sema/SemaARM.h index 104992e8826c3..1e8941a381dc5 100644 --- a/clang/include/clang/Sema/SemaARM.h +++ b/clang/include/clang/Sema/SemaARM.h @@ -96,6 +96,9 @@ class SemaARM : public SemaBase { bool checkTargetClonesAttr(SmallVectorImpl &Params, SmallVectorImpl &Locs, SmallVectorImpl> &NewParams); + bool checkSVETypeSupport(QualType Ty, SourceLocation Loc, + const FunctionDecl *FD, + const llvm::StringMap &FeatureMap); }; SemaARM::ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 46addea232b03..1541b2cc95d8c 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2254,16 +2254,10 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { } // Don't allow SVE types in functions without a SVE target. - if (Ty->isSVESizelessBuiltinType() && FD && !FD->getType().isNull()) { + if (Ty->isSVESizelessBuiltinType() && FD) { llvm::StringMap CallerFeatureMap; Context.getFunctionFeatureMap(CallerFeatureMap, FD); - if (!Builtin::evaluateRequiredTargetFeatures("sve", CallerFeatureMap)) { - if (!Builtin::evaluateRequiredTargetFeatures("sme", CallerFeatureMap)) - Diag(Loc, diag::err_sve_vector_in_non_sve_target) << Ty; - else if (!IsArmStreamingFunction(FD, - /*IncludeLocallyStreaming=*/true)) - Diag(Loc, diag::err_sve_vector_in_non_streaming_function) << Ty; - } + ARM().checkSVETypeSupport(Ty, Loc, FD, CallerFeatureMap); } if (auto *VT = Ty->getAs(); diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp index ab37394cd5f98..0a96f4f3bd170 100644 --- a/clang/lib/Sema/SemaARM.cpp +++ b/clang/lib/Sema/SemaARM.cpp @@ -1685,4 +1685,24 @@ bool SemaARM::checkTargetClonesAttr( return false; } +bool SemaARM::checkSVETypeSupport(QualType Ty, SourceLocation Loc, + const FunctionDecl *FD, + const llvm::StringMap &FeatureMap) { + if (!Ty->isSVESizelessBuiltinType()) + return false; + + if (FeatureMap.lookup("sve")) + return false; + + // No SVE environment available. + if (!FeatureMap.lookup("sme")) + return Diag(Loc, diag::err_sve_vector_in_non_sve_target) << Ty; + + // SVE environment only available to streaming functions. + if (FD && !FD->getType().isNull() && + !IsArmStreamingFunction(FD, /*IncludeLocallyStreaming=*/true)) + return Diag(Loc, diag::err_sve_vector_in_non_streaming_function) << Ty; + + return false; +} } // namespace clang diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 086dd8ba1c670..cef1a5c4b24f6 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9125,20 +9125,10 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { const FunctionDecl *FD = cast(CurContext); llvm::StringMap CallerFeatureMap; Context.getFunctionFeatureMap(CallerFeatureMap, FD); - - if (!Builtin::evaluateRequiredTargetFeatures("sve", CallerFeatureMap)) { - if (!Builtin::evaluateRequiredTargetFeatures("sme", CallerFeatureMap)) { - Diag(NewVD->getLocation(), diag::err_sve_vector_in_non_sve_target) << T; - NewVD->setInvalidDecl(); - return; - } else if (!IsArmStreamingFunction(FD, - /*IncludeLocallyStreaming=*/true)) { - Diag(NewVD->getLocation(), - diag::err_sve_vector_in_non_streaming_function) - << T; - NewVD->setInvalidDecl(); - return; - } + if (ARM().checkSVETypeSupport(T, NewVD->getLocation(), FD, + CallerFeatureMap)) { + NewVD->setInvalidDecl(); + return; } } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 2159a0dc2a5d7..b17402ecc2e68 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -4189,6 +4189,14 @@ static bool CheckVectorElementsTraitOperandType(Sema &S, QualType T, << "" << "__builtin_vectorelements" << T << ArgRange; + if (auto *FD = dyn_cast(S.CurContext)) { + if (T->isSVESizelessBuiltinType()) { + llvm::StringMap CallerFeatureMap; + S.Context.getFunctionFeatureMap(CallerFeatureMap, FD); + return S.ARM().checkSVETypeSupport(T, Loc, FD, CallerFeatureMap); + } + } + return false; } diff --git a/clang/test/Sema/AArch64/builtin_vectorelements.c b/clang/test/Sema/AArch64/builtin_vectorelements.c new file mode 100644 index 0000000000000..3391da3fc81e1 --- /dev/null +++ b/clang/test/Sema/AArch64/builtin_vectorelements.c @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -fsyntax-only -verify %s +// REQUIRES: aarch64-registered-target + +#include + +__attribute__((target("sve"))) +long test_builtin_vectorelements_sve(void) { + return __builtin_vectorelements(svuint8_t); +} + +__attribute__((target("sve2p1"))) +long test_builtin_vectorelements_sve2p1(void) { + return __builtin_vectorelements(svuint8_t); +} + +long test_builtin_vectorelements_no_sve(void) { + // expected-error@+1 {{SVE vector type 'svuint8_t' (aka '__SVUint8_t') cannot be used in a target without sve}} + return __builtin_vectorelements(svuint8_t); +} + +__attribute__((target("sme"))) +long test_builtin_vectorelements_sme_streaming(void) __arm_streaming { + return __builtin_vectorelements(svuint8_t); +} + +__attribute__((target("sme2p1"))) +long test_builtin_vectorelements_sme2p1_streaming(void) __arm_streaming { + return __builtin_vectorelements(svuint8_t); +} + +__attribute__((target("sme"))) +long test_builtin_vectorelements_sme(void) { + // expected-error@+1 {{SVE vector type 'svuint8_t' (aka '__SVUint8_t') cannot be used in a non-streaming function}} + return __builtin_vectorelements(svuint8_t); +} + +__attribute__((target("sve,sme"))) +long test_builtin_vectorelements_sve_sme_streaming_compatible(void) __arm_streaming_compatible { + return __builtin_vectorelements(svuint8_t); +} + +__attribute__((target("sme"))) +long test_builtin_vectorelements_sme_streaming_compatible(void) __arm_streaming_compatible { + // expected-error@+1 {{SVE vector type 'svuint8_t' (aka '__SVUint8_t') cannot be used in a non-streaming function}} + return __builtin_vectorelements(svuint8_t); +}