Skip to content

Commit 4e32271

Browse files
[AArch64][SME] Add diagnostics for SME attributes on lambda functions (#121777)
CheckFunctionDeclaration emits diagnostics if any SME attributes are used by a function definition without the required +sme or +sme2 target features. This patch moves these diagnostics to a new function in SemaARM and also adds a call to this from ActOnStartOfLambdaDefinition.
1 parent 4c853be commit 4e32271

File tree

5 files changed

+69
-53
lines changed

5 files changed

+69
-53
lines changed

clang/include/clang/Sema/SemaARM.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ class SemaARM : public SemaBase {
7979
void handleNewAttr(Decl *D, const ParsedAttr &AL);
8080
void handleCmseNSEntryAttr(Decl *D, const ParsedAttr &AL);
8181
void handleInterruptAttr(Decl *D, const ParsedAttr &AL);
82+
83+
void CheckSMEFunctionDefAttributes(const FunctionDecl *FD);
8284
};
8385

8486
SemaARM::ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD);

clang/lib/Sema/SemaARM.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,4 +1328,57 @@ void SemaARM::handleInterruptAttr(Decl *D, const ParsedAttr &AL) {
13281328
ARMInterruptAttr(getASTContext(), AL, Kind));
13291329
}
13301330

1331+
// Check if the function definition uses any AArch64 SME features without
1332+
// having the '+sme' feature enabled and warn user if sme locally streaming
1333+
// function returns or uses arguments with VL-based types.
1334+
void SemaARM::CheckSMEFunctionDefAttributes(const FunctionDecl *FD) {
1335+
const auto *Attr = FD->getAttr<ArmNewAttr>();
1336+
bool UsesSM = FD->hasAttr<ArmLocallyStreamingAttr>();
1337+
bool UsesZA = Attr && Attr->isNewZA();
1338+
bool UsesZT0 = Attr && Attr->isNewZT0();
1339+
1340+
if (FD->hasAttr<ArmLocallyStreamingAttr>()) {
1341+
if (FD->getReturnType()->isSizelessVectorType())
1342+
Diag(FD->getLocation(),
1343+
diag::warn_sme_locally_streaming_has_vl_args_returns)
1344+
<< /*IsArg=*/false;
1345+
if (llvm::any_of(FD->parameters(), [](ParmVarDecl *P) {
1346+
return P->getOriginalType()->isSizelessVectorType();
1347+
}))
1348+
Diag(FD->getLocation(),
1349+
diag::warn_sme_locally_streaming_has_vl_args_returns)
1350+
<< /*IsArg=*/true;
1351+
}
1352+
if (const auto *FPT = FD->getType()->getAs<FunctionProtoType>()) {
1353+
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
1354+
UsesSM |= EPI.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask;
1355+
UsesZA |= FunctionType::getArmZAState(EPI.AArch64SMEAttributes) !=
1356+
FunctionType::ARM_None;
1357+
UsesZT0 |= FunctionType::getArmZT0State(EPI.AArch64SMEAttributes) !=
1358+
FunctionType::ARM_None;
1359+
}
1360+
1361+
ASTContext &Context = getASTContext();
1362+
if (UsesSM || UsesZA) {
1363+
llvm::StringMap<bool> FeatureMap;
1364+
Context.getFunctionFeatureMap(FeatureMap, FD);
1365+
if (!FeatureMap.contains("sme")) {
1366+
if (UsesSM)
1367+
Diag(FD->getLocation(),
1368+
diag::err_sme_definition_using_sm_in_non_sme_target);
1369+
else
1370+
Diag(FD->getLocation(),
1371+
diag::err_sme_definition_using_za_in_non_sme_target);
1372+
}
1373+
}
1374+
if (UsesZT0) {
1375+
llvm::StringMap<bool> FeatureMap;
1376+
Context.getFunctionFeatureMap(FeatureMap, FD);
1377+
if (!FeatureMap.contains("sme2")) {
1378+
Diag(FD->getLocation(),
1379+
diag::err_sme_definition_using_zt0_in_non_sme2_target);
1380+
}
1381+
}
1382+
}
1383+
13311384
} // namespace clang

clang/lib/Sema/SemaDecl.cpp

Lines changed: 3 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "clang/Sema/ParsedTemplate.h"
4646
#include "clang/Sema/Scope.h"
4747
#include "clang/Sema/ScopeInfo.h"
48+
#include "clang/Sema/SemaARM.h"
4849
#include "clang/Sema/SemaCUDA.h"
4950
#include "clang/Sema/SemaHLSL.h"
5051
#include "clang/Sema/SemaInternal.h"
@@ -12297,58 +12298,8 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
1229712298
}
1229812299
}
1229912300

12300-
// Check if the function definition uses any AArch64 SME features without
12301-
// having the '+sme' feature enabled and warn user if sme locally streaming
12302-
// function returns or uses arguments with VL-based types.
12303-
if (DeclIsDefn) {
12304-
const auto *Attr = NewFD->getAttr<ArmNewAttr>();
12305-
bool UsesSM = NewFD->hasAttr<ArmLocallyStreamingAttr>();
12306-
bool UsesZA = Attr && Attr->isNewZA();
12307-
bool UsesZT0 = Attr && Attr->isNewZT0();
12308-
12309-
if (NewFD->hasAttr<ArmLocallyStreamingAttr>()) {
12310-
if (NewFD->getReturnType()->isSizelessVectorType())
12311-
Diag(NewFD->getLocation(),
12312-
diag::warn_sme_locally_streaming_has_vl_args_returns)
12313-
<< /*IsArg=*/false;
12314-
if (llvm::any_of(NewFD->parameters(), [](ParmVarDecl *P) {
12315-
return P->getOriginalType()->isSizelessVectorType();
12316-
}))
12317-
Diag(NewFD->getLocation(),
12318-
diag::warn_sme_locally_streaming_has_vl_args_returns)
12319-
<< /*IsArg=*/true;
12320-
}
12321-
if (const auto *FPT = NewFD->getType()->getAs<FunctionProtoType>()) {
12322-
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
12323-
UsesSM |=
12324-
EPI.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask;
12325-
UsesZA |= FunctionType::getArmZAState(EPI.AArch64SMEAttributes) !=
12326-
FunctionType::ARM_None;
12327-
UsesZT0 |= FunctionType::getArmZT0State(EPI.AArch64SMEAttributes) !=
12328-
FunctionType::ARM_None;
12329-
}
12330-
12331-
if (UsesSM || UsesZA) {
12332-
llvm::StringMap<bool> FeatureMap;
12333-
Context.getFunctionFeatureMap(FeatureMap, NewFD);
12334-
if (!FeatureMap.contains("sme")) {
12335-
if (UsesSM)
12336-
Diag(NewFD->getLocation(),
12337-
diag::err_sme_definition_using_sm_in_non_sme_target);
12338-
else
12339-
Diag(NewFD->getLocation(),
12340-
diag::err_sme_definition_using_za_in_non_sme_target);
12341-
}
12342-
}
12343-
if (UsesZT0) {
12344-
llvm::StringMap<bool> FeatureMap;
12345-
Context.getFunctionFeatureMap(FeatureMap, NewFD);
12346-
if (!FeatureMap.contains("sme2")) {
12347-
Diag(NewFD->getLocation(),
12348-
diag::err_sme_definition_using_zt0_in_non_sme2_target);
12349-
}
12350-
}
12351-
}
12301+
if (DeclIsDefn && Context.getTargetInfo().getTriple().isAArch64())
12302+
ARM().CheckSMEFunctionDefAttributes(NewFD);
1235212303

1235312304
return Redeclaration;
1235412305
}

clang/lib/Sema/SemaLambda.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "clang/Sema/Lookup.h"
2222
#include "clang/Sema/Scope.h"
2323
#include "clang/Sema/ScopeInfo.h"
24+
#include "clang/Sema/SemaARM.h"
2425
#include "clang/Sema/SemaCUDA.h"
2526
#include "clang/Sema/SemaInternal.h"
2627
#include "clang/Sema/SemaOpenMP.h"
@@ -1455,6 +1456,9 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
14551456
// Attributes on the lambda apply to the method.
14561457
ProcessDeclAttributes(CurScope, Method, ParamInfo);
14571458

1459+
if (Context.getTargetInfo().getTriple().isAArch64())
1460+
ARM().CheckSMEFunctionDefAttributes(Method);
1461+
14581462
// CUDA lambdas get implicit host and device attributes.
14591463
if (getLangOpts().CUDA)
14601464
CUDA().SetLambdaAttrs(Method);

clang/test/Sema/aarch64-sme-func-attrs-without-target-feature.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -fsyntax-only -verify %s
1+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -std=c++23 -fsyntax-only -verify %s
22

33
// This test is testing the diagnostics that Clang emits when compiling without '+sme'.
44

@@ -48,3 +48,9 @@ void streaming_compatible_def2(void (*streaming_fn_ptr)(void) __arm_streaming,
4848
// Also test when call-site is not a function.
4949
int streaming_decl_ret_int() __arm_streaming;
5050
int x = streaming_decl_ret_int(); // expected-error {{call to a streaming function requires 'sme'}}
51+
52+
void sme_attrs_lambdas() {
53+
[] __arm_locally_streaming () { return; }(); // expected-error {{function executed in streaming-SVE mode requires 'sme'}}
54+
[] __arm_new("za") () { return; }(); // expected-error {{function using ZA state requires 'sme'}}
55+
[] __arm_new("zt0") () { return; }(); // expected-error {{function using ZT0 state requires 'sme2'}}
56+
}

0 commit comments

Comments
 (0)