Index: clang/include/clang/AST/Type.h =================================================================== --- clang/include/clang/AST/Type.h +++ clang/include/clang/AST/Type.h @@ -2002,6 +2002,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 @@ -3039,6 +3039,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.cpp =================================================================== --- clang/lib/Basic/Targets/AArch64.cpp +++ clang/lib/Basic/Targets/AArch64.cpp @@ -544,6 +544,23 @@ for (llvm::AArch64::ArchKind I = --AK; I != llvm::AArch64::ArchKind::INVALID; --I) Features[llvm::AArch64::getSubArch(I)] = Enabled; + + // FIXME: These dependencies between architecture features would be better + // modelled in the TargetParser, which should happen in a later patch. + 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::handleTargetFeatures(std::vector &Features, Index: clang/lib/Sema/Sema.cpp =================================================================== --- clang/lib/Sema/Sema.cpp +++ clang/lib/Sema/Sema.cpp @@ -2029,6 +2029,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 @@ -8597,6 +8597,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/CodeGen/aarch64-targetattr.c =================================================================== --- clang/test/CodeGen/aarch64-targetattr.c +++ clang/test/CodeGen/aarch64-targetattr.c @@ -10,85 +10,85 @@ // CHECK-LABEL: @v82sve2() #2 __attribute__((target("arch=armv8.2-a+sve2"))) void v82sve2() {} -// CHECK-LABEL: @v82svesve2() #3 +// CHECK-LABEL: @v82svesve2() #2 __attribute__((target("arch=armv8.2-a+sve+sve2"))) void v82svesve2() {} -// CHECK-LABEL: @v86sve2() #4 +// CHECK-LABEL: @v86sve2() #3 __attribute__((target("arch=armv8.6-a+sve2"))) void v86sve2() {} -// CHECK-LABEL: @a710() #5 +// CHECK-LABEL: @a710() #4 __attribute__((target("cpu=cortex-a710"))) void a710() {} -// CHECK-LABEL: @tunea710() #6 +// CHECK-LABEL: @tunea710() #5 __attribute__((target("tune=cortex-a710"))) void tunea710() {} -// CHECK-LABEL: @generic() #7 +// CHECK-LABEL: @generic() #6 __attribute__((target("cpu=generic"))) void generic() {} -// CHECK-LABEL: @tune() #8 +// CHECK-LABEL: @tune() #7 __attribute__((target("tune=generic"))) void tune() {} -// CHECK-LABEL: @n1tunea710() #9 +// CHECK-LABEL: @n1tunea710() #8 __attribute__((target("cpu=neoverse-n1,tune=cortex-a710"))) void n1tunea710() {} -// CHECK-LABEL: @svetunea710() #10 +// CHECK-LABEL: @svetunea710() #9 __attribute__((target("sve,tune=cortex-a710"))) void svetunea710() {} -// CHECK-LABEL: @plussvetunea710() #10 +// CHECK-LABEL: @plussvetunea710() #9 __attribute__((target("+sve,tune=cortex-a710"))) void plussvetunea710() {} -// CHECK-LABEL: @v1plussve2() #11 +// CHECK-LABEL: @v1plussve2() #10 __attribute__((target("cpu=neoverse-v1,+sve2"))) void v1plussve2() {} -// CHECK-LABEL: @v1sve2() #11 +// CHECK-LABEL: @v1sve2() #10 __attribute__((target("cpu=neoverse-v1+sve2"))) void v1sve2() {} -// CHECK-LABEL: @v1minussve() #12 +// CHECK-LABEL: @v1minussve() #11 __attribute__((target("cpu=neoverse-v1,+nosve"))) void v1minussve() {} -// CHECK-LABEL: @v1nosve() #12 +// CHECK-LABEL: @v1nosve() #11 __attribute__((target("cpu=neoverse-v1,no-sve"))) void v1nosve() {} -// CHECK-LABEL: @v1msve() #12 +// CHECK-LABEL: @v1msve() #11 __attribute__((target("cpu=neoverse-v1+nosve"))) void v1msve() {} -// CHECK-LABEL: @plussve() #13 +// CHECK-LABEL: @plussve() #12 __attribute__((target("+sve"))) void plussve() {} -// CHECK-LABEL: @plussveplussve2() #14 +// CHECK-LABEL: @plussveplussve2() #13 __attribute__((target("+sve+nosve2"))) void plussveplussve2() {} -// CHECK-LABEL: @plussveminusnosve2() #14 +// CHECK-LABEL: @plussveminusnosve2() #13 __attribute__((target("sve,no-sve2"))) void plussveminusnosve2() {} -// CHECK-LABEL: @plusfp16() #15 +// CHECK-LABEL: @plusfp16() #14 __attribute__((target("+fp16"))) void plusfp16() {} -// CHECK-LABEL: @all() #16 +// CHECK-LABEL: @all() #15 __attribute__((target("cpu=neoverse-n1,tune=cortex-a710,arch=armv8.6-a+sve2"))) void all() {} -// CHECK-LABEL: @allplusbranchprotection() #17 +// CHECK-LABEL: @allplusbranchprotection() #16 __attribute__((target("cpu=neoverse-n1,tune=cortex-a710,arch=armv8.6-a+sve2,branch-protection=standard"))) void allplusbranchprotection() {} // CHECK: attributes #0 = { {{.*}} "target-features"="+v8.1a,+v8.2a,+v8a" } // CHECK: attributes #1 = { {{.*}} "target-features"="+sve,+v8.1a,+v8.2a,+v8a" } -// CHECK: attributes #2 = { {{.*}} "target-features"="+sve2,+v8.1a,+v8.2a,+v8a" } -// CHECK: attributes #4 = { {{.*}} "target-features"="+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8.6a,+v8a" } -// CHECK: attributes #5 = { {{.*}} "target-cpu"="cortex-a710" "target-features"="+bf16,+crc,+dotprod,+flagm,+fp-armv8,+fp16fml,+i8mm,+lse,+mte,+neon,+pauth,+ras,+rcpc,+rdm,+sb,+sve,+sve2,+sve2-bitperm" } -// CHECK: attributes #6 = { {{.*}} "tune-cpu"="cortex-a710" } -// CHECK: attributes #7 = { {{.*}} "target-cpu"="generic" } -// CHECK: attributes #8 = { {{.*}} "tune-cpu"="generic" } -// CHECK: attributes #9 = { {{.*}} "target-cpu"="neoverse-n1" "target-features"="+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+spe,+ssbs" "tune-cpu"="cortex-a710" } -// CHECK: attributes #10 = { {{.*}} "target-features"="+sve" "tune-cpu"="cortex-a710" } -// CHECK: attributes #11 = { {{.*}} "target-cpu"="neoverse-v1" "target-features"="+bf16,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+lse,+neon,+rand,+ras,+rcpc,+rdm,+spe,+ssbs,+sve,+sve2" } -// CHECK: attributes #12 = { {{.*}} "target-cpu"="neoverse-v1" "target-features"="+bf16,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+lse,+neon,+rand,+ras,+rcpc,+rdm,+spe,+ssbs,-sve" } -// CHECK: attributes #13 = { {{.*}} "target-features"="+sve" } -// CHECK: attributes #14 = { {{.*}} "target-features"="+sve,-sve2" } -// CHECK: attributes #15 = { {{.*}} "target-features"="+fullfp16" } -// CHECK: attributes #16 = { {{.*}} "target-cpu"="neoverse-n1" "target-features"="+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+spe,+ssbs,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8.6a,+v8a" "tune-cpu"="cortex-a710" } -// CHECK: attributes #17 = { {{.*}} "branch-target-enforcement"="true" {{.*}} "target-cpu"="neoverse-n1" "target-features"="+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+spe,+ssbs,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8.6a,+v8a" "tune-cpu"="cortex-a710" } +// CHECK: attributes #2 = { {{.*}} "target-features"="+sve,+sve2,+v8.1a,+v8.2a,+v8a" } +// CHECK: attributes #3 = { {{.*}} "target-features"="+sve,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8.6a,+v8a" } +// CHECK: attributes #4 = { {{.*}} "target-cpu"="cortex-a710" "target-features"="+bf16,+crc,+dotprod,+flagm,+fp-armv8,+fp16fml,+i8mm,+lse,+mte,+neon,+pauth,+ras,+rcpc,+rdm,+sb,+sve,+sve2,+sve2-bitperm" } +// CHECK: attributes #5 = { {{.*}} "tune-cpu"="cortex-a710" } +// CHECK: attributes #6 = { {{.*}} "target-cpu"="generic" } +// CHECK: attributes #7 = { {{.*}} "tune-cpu"="generic" } +// CHECK: attributes #8 = { {{.*}} "target-cpu"="neoverse-n1" "target-features"="+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+spe,+ssbs" "tune-cpu"="cortex-a710" } +// CHECK: attributes #9 = { {{.*}} "target-features"="+sve" "tune-cpu"="cortex-a710" } +// CHECK: attributes #10 = { {{.*}} "target-cpu"="neoverse-v1" "target-features"="+bf16,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+lse,+neon,+rand,+ras,+rcpc,+rdm,+spe,+ssbs,+sve,+sve2" } +// CHECK: attributes #11 = { {{.*}} "target-cpu"="neoverse-v1" "target-features"="+bf16,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+lse,+neon,+rand,+ras,+rcpc,+rdm,+spe,+ssbs,-sve,-sve2,-sve2-aes,-sve2-bitperm,-sve2-sha3,-sve2-sm4" } +// CHECK: attributes #12 = { {{.*}} "target-features"="+sve" } +// CHECK: attributes #13 = { {{.*}} "target-features"="+sve,-sve2,-sve2-aes,-sve2-bitperm,-sve2-sha3,-sve2-sm4" } +// CHECK: attributes #14 = { {{.*}} "target-features"="+fullfp16" } +// CHECK: attributes #15 = { {{.*}} "target-cpu"="neoverse-n1" "target-features"="+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+spe,+ssbs,+sve,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8.6a,+v8a" "tune-cpu"="cortex-a710" } +// CHECK: attributes #16 = { {{.*}} "branch-target-enforcement"="true" {{.*}} "target-cpu"="neoverse-n1" "target-features"="+crc,+crypto,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+spe,+ssbs,+sve,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8.6a,+v8a" "tune-cpu"="cortex-a710" } 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; +} +