diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index b4dc4feee8e63..83b89d1449f42 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3728,6 +3728,8 @@ def err_sme_definition_using_zt0_in_non_sme2_target : Error< "function using ZT0 state requires 'sme2'">; def err_conflicting_attributes_arm_state : Error< "conflicting attributes for state '%0'">; +def err_sme_streaming_cannot_be_multiversioned : Error< + "streaming function cannot be multi-versioned">; def err_unknown_arm_state : Error< "unknown state '%0'">; def err_missing_arm_state : Error< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 851560f759f0e..32f7202f68958 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4838,13 +4838,12 @@ class Sema final { llvm::Error isValidSectionSpecifier(StringRef Str); bool checkSectionName(SourceLocation LiteralLoc, StringRef Str); bool checkTargetAttr(SourceLocation LiteralLoc, StringRef Str); - bool checkTargetVersionAttr(SourceLocation LiteralLoc, StringRef &Str, - bool &isDefault); - bool - checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str, - const StringLiteral *Literal, bool &HasDefault, - bool &HasCommas, bool &HasNotDefault, - SmallVectorImpl> &StringsBuffer); + bool checkTargetVersionAttr(SourceLocation LiteralLoc, Decl *D, + StringRef &Str, bool &isDefault); + bool checkTargetClonesAttrString( + SourceLocation LiteralLoc, StringRef Str, const StringLiteral *Literal, + Decl *D, bool &HasDefault, bool &HasCommas, bool &HasNotDefault, + SmallVectorImpl> &StringsBuffer); bool checkMSInheritanceAttrOnDefinition( CXXRecordDecl *RD, SourceRange Range, bool BestCase, MSInheritanceModel SemanticSpelling); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index d785714c4d811..d5526957937bb 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3501,9 +3501,16 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { return false; } +static bool hasArmStreamingInterface(const FunctionDecl *FD) { + if (const auto *T = FD->getType()->getAs()) + if (T->getAArch64SMEAttributes() & FunctionType::SME_PStateSMEnabledMask) + return true; + return false; +} + // Check Target Version attrs -bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, StringRef &AttrStr, - bool &isDefault) { +bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, Decl *D, + StringRef &AttrStr, bool &isDefault) { enum FirstParam { Unsupported }; enum SecondParam { None }; enum ThirdParam { Target, TargetClones, TargetVersion }; @@ -3519,6 +3526,8 @@ bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, StringRef &AttrStr, return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << CurFeature << TargetVersion; } + if (hasArmStreamingInterface(cast(D))) + return Diag(LiteralLoc, diag::err_sme_streaming_cannot_be_multiversioned); return false; } @@ -3527,7 +3536,7 @@ static void handleTargetVersionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { SourceLocation LiteralLoc; bool isDefault = false; if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc) || - S.checkTargetVersionAttr(LiteralLoc, Str, isDefault)) + S.checkTargetVersionAttr(LiteralLoc, D, Str, isDefault)) return; // Do not create default only target_version attribute if (!isDefault) { @@ -3550,7 +3559,7 @@ static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) { bool Sema::checkTargetClonesAttrString( SourceLocation LiteralLoc, StringRef Str, const StringLiteral *Literal, - bool &HasDefault, bool &HasCommas, bool &HasNotDefault, + Decl *D, bool &HasDefault, bool &HasCommas, bool &HasNotDefault, SmallVectorImpl> &StringsBuffer) { enum FirstParam { Unsupported, Duplicate, Unknown }; enum SecondParam { None, CPU, Tune }; @@ -3619,6 +3628,9 @@ bool Sema::checkTargetClonesAttrString( HasNotDefault = true; } } + if (hasArmStreamingInterface(cast(D))) + return Diag(LiteralLoc, + diag::err_sme_streaming_cannot_be_multiversioned); } else { // Other targets ( currently X86 ) if (Cur.starts_with("arch=")) { @@ -3670,7 +3682,7 @@ static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!S.checkStringLiteralArgumentAttr(AL, I, CurStr, &LiteralLoc) || S.checkTargetClonesAttrString( LiteralLoc, CurStr, - cast(AL.getArgAsExpr(I)->IgnoreParenCasts()), + cast(AL.getArgAsExpr(I)->IgnoreParenCasts()), D, HasDefault, HasCommas, HasNotDefault, StringsBuffer)) return; } diff --git a/clang/test/Sema/aarch64-sme-func-attrs.c b/clang/test/Sema/aarch64-sme-func-attrs.c index 2bf1886951f1f..47dbeca206a94 100644 --- a/clang/test/Sema/aarch64-sme-func-attrs.c +++ b/clang/test/Sema/aarch64-sme-func-attrs.c @@ -454,3 +454,43 @@ void unimplemented_spill_fill_za(void (*share_zt0_only)(void) __arm_inout("zt0") // expected-note@+1 {{add '__arm_preserves("za")' to the callee if it preserves ZA}} share_zt0_only(); } + +// expected-cpp-error@+2 {{streaming function cannot be multi-versioned}} +// expected-error@+1 {{streaming function cannot be multi-versioned}} +__attribute__((target_version("sme2"))) +void cannot_work_version(void) __arm_streaming {} +// expected-cpp-error@+5 {{function declared 'void ()' was previously declared 'void () __arm_streaming', which has different SME function attributes}} +// expected-cpp-note@-2 {{previous declaration is here}} +// expected-error@+3 {{function declared 'void (void)' was previously declared 'void (void) __arm_streaming', which has different SME function attributes}} +// expected-note@-4 {{previous declaration is here}} +__attribute__((target_version("default"))) +void cannot_work_version(void) {} + + +// expected-cpp-error@+2 {{streaming function cannot be multi-versioned}} +// expected-error@+1 {{streaming function cannot be multi-versioned}} +__attribute__((target_clones("sme2"))) +void cannot_work_clones(void) __arm_streaming {} + + +__attribute__((target("sme2"))) +void just_fine_streaming(void) __arm_streaming {} +__attribute__((target_version("sme2"))) +void just_fine(void) { just_fine_streaming(); } +__attribute__((target_version("default"))) +void just_fine(void) {} + + +__arm_locally_streaming +__attribute__((target_version("sme2"))) +void just_fine_locally_streaming(void) {} +__attribute__((target_version("default"))) +void just_fine_locally_streaming(void) {} + + +void fmv_caller() { + cannot_work_version(); + cannot_work_clones(); + just_fine(); + just_fine_locally_streaming(); +}