Skip to content

Commit 4e85e1f

Browse files
author
Dinar Temirbulatov
authored
[Clang][AArch64] Warn when calling non/streaming about vector size difference (#79842)
The compiler doesn't know in advance if the streaming and non-streaming vector-lengths are different, so it should be safe to give a warning diagnostic to warn the user about possible undefined behaviour. If the user knows the vector lengths are equal, they can disable the warning separately.
1 parent 299b636 commit 4e85e1f

File tree

6 files changed

+184
-5
lines changed

6 files changed

+184
-5
lines changed

clang/include/clang/Basic/DiagnosticGroups.td

+3
Original file line numberDiff line numberDiff line change
@@ -1412,6 +1412,9 @@ def MultiGPU: DiagGroup<"multi-gpu">;
14121412
// libc and the CRT to be skipped.
14131413
def AVRRtlibLinkingQuirks : DiagGroup<"avr-rtlib-linking-quirks">;
14141414

1415+
// A warning group related to AArch64 SME function attribues.
1416+
def AArch64SMEAttributes : DiagGroup<"aarch64-sme-attributes">;
1417+
14151418
// A warning group for things that will change semantics in the future.
14161419
def FutureCompat : DiagGroup<"future-compat">;
14171420

clang/include/clang/Basic/DiagnosticSemaKinds.td

+10
Original file line numberDiff line numberDiff line change
@@ -3755,6 +3755,16 @@ def err_sme_definition_using_za_in_non_sme_target : Error<
37553755
"function using ZA state requires 'sme'">;
37563756
def err_sme_definition_using_zt0_in_non_sme2_target : Error<
37573757
"function using ZT0 state requires 'sme2'">;
3758+
def warn_sme_streaming_pass_return_vl_to_non_streaming : Warning<
3759+
"passing a VL-dependent argument to/from a function that has a different"
3760+
" streaming-mode. The streaming and non-streaming vector lengths may be"
3761+
" different">,
3762+
InGroup<AArch64SMEAttributes>, DefaultIgnore;
3763+
def warn_sme_locally_streaming_has_vl_args_returns : Warning<
3764+
"passing/returning a VL-dependent argument to/from a __arm_locally_streaming"
3765+
" function. The streaming and non-streaming vector"
3766+
" lengths may be different">,
3767+
InGroup<AArch64SMEAttributes>, DefaultIgnore;
37583768
def err_conflicting_attributes_arm_state : Error<
37593769
"conflicting attributes for state '%0'">;
37603770
def err_sme_streaming_cannot_be_multiversioned : Error<

clang/lib/Sema/SemaChecking.cpp

+21-1
Original file line numberDiff line numberDiff line change
@@ -7938,6 +7938,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
79387938
// For variadic functions, we may have more args than parameters.
79397939
// For some K&R functions, we may have less args than parameters.
79407940
const auto N = std::min<unsigned>(Proto->getNumParams(), Args.size());
7941+
bool AnyScalableArgsOrRet = Proto->getReturnType()->isSizelessVectorType();
79417942
for (unsigned ArgIdx = 0; ArgIdx < N; ++ArgIdx) {
79427943
// Args[ArgIdx] can be null in malformed code.
79437944
if (const Expr *Arg = Args[ArgIdx]) {
@@ -7951,6 +7952,8 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
79517952
checkAIXMemberAlignment((Arg->getExprLoc()), Arg);
79527953

79537954
QualType ParamTy = Proto->getParamType(ArgIdx);
7955+
if (ParamTy->isSizelessVectorType())
7956+
AnyScalableArgsOrRet = true;
79547957
QualType ArgTy = Arg->getType();
79557958
CheckArgAlignment(Arg->getExprLoc(), FDecl, std::to_string(ArgIdx + 1),
79567959
ArgTy, ParamTy);
@@ -7971,6 +7974,23 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
79717974
}
79727975
}
79737976

7977+
// If the call requires a streaming-mode change and has scalable vector
7978+
// arguments or return values, then warn the user that the streaming and
7979+
// non-streaming vector lengths may be different.
7980+
const auto *CallerFD = dyn_cast<FunctionDecl>(CurContext);
7981+
if (CallerFD && (!FD || !FD->getBuiltinID()) && AnyScalableArgsOrRet) {
7982+
bool IsCalleeStreaming =
7983+
ExtInfo.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask;
7984+
bool IsCalleeStreamingCompatible =
7985+
ExtInfo.AArch64SMEAttributes &
7986+
FunctionType::SME_PStateSMCompatibleMask;
7987+
ArmStreamingType CallerFnType = getArmStreamingFnType(CallerFD);
7988+
if (!IsCalleeStreamingCompatible &&
7989+
(CallerFnType == ArmStreamingCompatible ||
7990+
((CallerFnType == ArmStreaming) ^ IsCalleeStreaming)))
7991+
Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming);
7992+
}
7993+
79747994
FunctionType::ArmStateValue CalleeArmZAState =
79757995
FunctionType::getArmZAState(ExtInfo.AArch64SMEAttributes);
79767996
FunctionType::ArmStateValue CalleeArmZT0State =
@@ -7979,7 +7999,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
79797999
CalleeArmZT0State != FunctionType::ARM_None) {
79808000
bool CallerHasZAState = false;
79818001
bool CallerHasZT0State = false;
7982-
if (const auto *CallerFD = dyn_cast<FunctionDecl>(CurContext)) {
8002+
if (CallerFD) {
79838003
auto *Attr = CallerFD->getAttr<ArmNewAttr>();
79848004
if (Attr && Attr->isNewZA())
79858005
CallerHasZAState = true;

clang/lib/Sema/SemaDecl.cpp

+11-1
Original file line numberDiff line numberDiff line change
@@ -12395,12 +12395,22 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
1239512395
}
1239612396

1239712397
// Check if the function definition uses any AArch64 SME features without
12398-
// having the '+sme' feature enabled.
12398+
// having the '+sme' feature enabled and warn user if sme locally streaming
12399+
// function returns or uses arguments with VL-based types.
1239912400
if (DeclIsDefn) {
1240012401
const auto *Attr = NewFD->getAttr<ArmNewAttr>();
1240112402
bool UsesSM = NewFD->hasAttr<ArmLocallyStreamingAttr>();
1240212403
bool UsesZA = Attr && Attr->isNewZA();
1240312404
bool UsesZT0 = Attr && Attr->isNewZT0();
12405+
12406+
if (NewFD->hasAttr<ArmLocallyStreamingAttr>()) {
12407+
if (NewFD->getReturnType()->isSizelessVectorType() ||
12408+
llvm::any_of(NewFD->parameters(), [](ParmVarDecl *P) {
12409+
return P->getOriginalType()->isSizelessVectorType();
12410+
}))
12411+
Diag(NewFD->getLocation(),
12412+
diag::warn_sme_locally_streaming_has_vl_args_returns);
12413+
}
1240412414
if (const auto *FPT = NewFD->getType()->getAs<FunctionProtoType>()) {
1240512415
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
1240612416
UsesSM |=

clang/test/Sema/aarch64-incompat-sm-builtin-calls.c

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
22
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve \
3-
// RUN: -target-feature +sme2 -target-feature +sve2 -target-feature +neon -fsyntax-only -verify %s
3+
// RUN: -target-feature +sme2 -target-feature +sve2 -target-feature +neon -Waarch64-sme-attributes -fsyntax-only -verify %s
44

55
// REQUIRES: aarch64-registered-target
66

@@ -33,6 +33,7 @@ svuint32_t incompat_sve_sm(svbool_t pg, svuint32_t a, int16_t b) __arm_streaming
3333
return __builtin_sve_svld1_gather_u32base_index_u32(pg, a, b);
3434
}
3535

36+
// expected-warning@+1 {{passing/returning a VL-dependent argument to/from a __arm_locally_streaming function. The streaming and non-streaming vector lengths may be different}}
3637
__arm_locally_streaming svuint32_t incompat_sve_ls(svbool_t pg, svuint32_t a, int64_t b) {
3738
// expected-warning@+1 {{builtin call has undefined behaviour when called from a streaming function}}
3839
return __builtin_sve_svld1_gather_u32base_index_u32(pg, a, b);
@@ -48,6 +49,7 @@ svuint32_t incompat_sve2_sm(svbool_t pg, svuint32_t a, int64_t b) __arm_streamin
4849
return __builtin_sve_svldnt1_gather_u32base_index_u32(pg, a, b);
4950
}
5051

52+
// expected-warning@+1 {{passing/returning a VL-dependent argument to/from a __arm_locally_streaming function. The streaming and non-streaming vector lengths may be different}}
5153
__arm_locally_streaming svuint32_t incompat_sve2_ls(svbool_t pg, svuint32_t a, int64_t b) {
5254
// expected-warning@+1 {{builtin call has undefined behaviour when called from a streaming function}}
5355
return __builtin_sve_svldnt1_gather_u32base_index_u32(pg, a, b);
@@ -68,6 +70,7 @@ svfloat64_t streaming_caller_sve(svbool_t pg, svfloat64_t a, float64_t b) __arm_
6870
return svadd_n_f64_m(pg, a, b);
6971
}
7072

73+
// expected-warning@+1 {{passing/returning a VL-dependent argument to/from a __arm_locally_streaming function. The streaming and non-streaming vector lengths may be different}}
7174
__arm_locally_streaming svfloat64_t locally_streaming_caller_sve(svbool_t pg, svfloat64_t a, float64_t b) {
7275
// expected-no-warning
7376
return svadd_n_f64_m(pg, a, b);
@@ -83,6 +86,7 @@ svint16_t streaming_caller_sve2(svint16_t op1, svint16_t op2) __arm_streaming {
8386
return svmul_lane_s16(op1, op2, 0);
8487
}
8588

89+
// expected-warning@+1 {{passing/returning a VL-dependent argument to/from a __arm_locally_streaming function. The streaming and non-streaming vector lengths may be different}}
8690
__arm_locally_streaming svint16_t locally_streaming_caller_sve2(svint16_t op1, svint16_t op2) {
8791
// expected-no-warning
8892
return svmul_lane_s16(op1, op2, 0);

clang/test/Sema/aarch64-sme-func-attrs.c

+134-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme2 -fsyntax-only -verify %s
2-
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme2 -fsyntax-only -verify=expected-cpp -x c++ %s
1+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme2 -target-feature +sve -Waarch64-sme-attributes -fsyntax-only -verify %s
2+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme2 -target-feature +sve -Waarch64-sme-attributes -fsyntax-only -verify=expected-cpp -x c++ %s
33

44
// Valid attributes
55

@@ -496,3 +496,135 @@ void fmv_caller() {
496496
just_fine();
497497
incompatible_locally_streaming();
498498
}
499+
500+
void sme_streaming_with_vl_arg(__SVInt8_t a) __arm_streaming { }
501+
502+
__SVInt8_t sme_streaming_returns_vl(void) __arm_streaming { __SVInt8_t r; return r; }
503+
504+
void sme_streaming_compatible_with_vl_arg(__SVInt8_t a) __arm_streaming_compatible { }
505+
506+
__SVInt8_t sme_streaming_compatible_returns_vl(void) __arm_streaming_compatible { __SVInt8_t r; return r; }
507+
508+
void sme_no_streaming_with_vl_arg(__SVInt8_t a) { }
509+
510+
__SVInt8_t sme_no_streaming_returns_vl(void) { __SVInt8_t r; return r; }
511+
512+
// expected-warning@+2 {{passing/returning a VL-dependent argument to/from a __arm_locally_streaming function. The streaming and non-streaming vector lengths may be different}}
513+
// expected-cpp-warning@+1 {{passing/returning a VL-dependent argument to/from a __arm_locally_streaming function. The streaming and non-streaming vector lengths may be different}}
514+
__arm_locally_streaming void sme_locally_streaming_with_vl_arg(__SVInt8_t a) { }
515+
516+
// expected-warning@+2 {{passing/returning a VL-dependent argument to/from a __arm_locally_streaming function. The streaming and non-streaming vector lengths may be different}}
517+
// expected-cpp-warning@+1 {{passing/returning a VL-dependent argument to/from a __arm_locally_streaming function. The streaming and non-streaming vector lengths may be different}}
518+
__arm_locally_streaming __SVInt8_t sme_locally_streaming_returns_vl(void) { __SVInt8_t r; return r; }
519+
520+
void sme_no_streaming_calling_streaming_with_vl_args() {
521+
__SVInt8_t a;
522+
// expected-warning@+2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
523+
// expected-cpp-warning@+1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
524+
sme_streaming_with_vl_arg(a);
525+
}
526+
527+
void sme_no_streaming_calling_streaming_with_return_vl() {
528+
// expected-warning@+2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
529+
// expected-cpp-warning@+1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
530+
__SVInt8_t r = sme_streaming_returns_vl();
531+
}
532+
533+
void sme_streaming_calling_non_streaming_with_vl_args(void) __arm_streaming {
534+
__SVInt8_t a;
535+
// expected-warning@+2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
536+
// expected-cpp-warning@+1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
537+
sme_no_streaming_with_vl_arg(a);
538+
}
539+
540+
void sme_streaming_calling_non_streaming_with_return_vl(void) __arm_streaming {
541+
// expected-warning@+2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
542+
// expected-cpp-warning@+1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
543+
__SVInt8_t r = sme_no_streaming_returns_vl();
544+
}
545+
546+
void sme_no_streaming_calling_streaming_with_vl_args_param(__SVInt8_t arg, void (*sc)( __SVInt8_t arg) __arm_streaming) {
547+
// expected-warning@+2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
548+
// expected-cpp-warning@+1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
549+
sc(arg);
550+
}
551+
552+
__SVInt8_t sme_no_streaming_calling_streaming_return_vl_param(__SVInt8_t (*s)(void) __arm_streaming) {
553+
// expected-warning@+2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
554+
// expected-cpp-warning@+1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
555+
return s();
556+
}
557+
558+
void sme_streaming_compatible_calling_streaming_with_vl_args(__SVInt8_t arg) __arm_streaming_compatible {
559+
// expected-warning@+2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
560+
// expected-cpp-warning@+1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
561+
sme_streaming_with_vl_arg(arg);
562+
}
563+
564+
void sme_streaming_compatible_calling_sme_streaming_return_vl(void) __arm_streaming_compatible {
565+
// expected-warning@+2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
566+
// expected-cpp-warning@+1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
567+
__SVInt8_t r = sme_streaming_returns_vl();
568+
}
569+
570+
void sme_streaming_compatible_calling_no_streaming_with_vl_args(__SVInt8_t arg) __arm_streaming_compatible {
571+
// expected-warning@+2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
572+
// expected-cpp-warning@+1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
573+
sme_no_streaming_with_vl_arg(arg);
574+
}
575+
576+
void sme_streaming_compatible_calling_no_sme_streaming_return_vl(void) __arm_streaming_compatible {
577+
// expected-warning@+2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
578+
// expected-cpp-warning@+1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
579+
__SVInt8_t r = sme_no_streaming_returns_vl();
580+
}
581+
582+
void sme_streaming_calling_streaming(__SVInt8_t arg, void (*s)( __SVInt8_t arg) __arm_streaming) __arm_streaming {
583+
s(arg);
584+
}
585+
586+
__SVInt8_t sme_streaming_calling_streaming_return_vl(__SVInt8_t (*s)(void) __arm_streaming) __arm_streaming {
587+
return s();
588+
}
589+
590+
void sme_streaming_calling_streaming_with_vl_args(__SVInt8_t a) __arm_streaming {
591+
sme_streaming_with_vl_arg(a);
592+
}
593+
594+
void sme_streaming_calling_streaming_with_return_vl(void) __arm_streaming {
595+
__SVInt8_t r = sme_streaming_returns_vl();
596+
}
597+
598+
void sme_streaming_calling_streaming_compatible_with_vl_args(__SVInt8_t a) __arm_streaming {
599+
sme_streaming_compatible_with_vl_arg(a);
600+
}
601+
602+
void sme_streaming_calling_streaming_compatible_with_return_vl(void) __arm_streaming {
603+
__SVInt8_t r = sme_streaming_compatible_returns_vl();
604+
}
605+
606+
void sme_no_streaming_calling_streaming_compatible_with_vl_args() {
607+
__SVInt8_t a;
608+
sme_streaming_compatible_with_vl_arg(a);
609+
}
610+
611+
void sme_no_streaming_calling_streaming_compatible_with_return_vl() {
612+
__SVInt8_t r = sme_streaming_compatible_returns_vl();
613+
}
614+
615+
void sme_no_streaming_calling_non_streaming_compatible_with_vl_args() {
616+
__SVInt8_t a;
617+
sme_no_streaming_with_vl_arg(a);
618+
}
619+
620+
void sme_no_streaming_calling_non_streaming_compatible_with_return_vl() {
621+
__SVInt8_t r = sme_no_streaming_returns_vl();
622+
}
623+
624+
void sme_streaming_compatible_calling_streaming_compatible_with_vl_args(__SVInt8_t arg) __arm_streaming_compatible {
625+
sme_streaming_compatible_with_vl_arg(arg);
626+
}
627+
628+
void sme_streaming_compatible_calling_streaming_compatible_with_return_vl(void) __arm_streaming_compatible {
629+
__SVInt8_t r = sme_streaming_compatible_returns_vl();
630+
}

0 commit comments

Comments
 (0)