https://github.com/dtemirbulatov created https://github.com/llvm/llvm-project/pull/79842
…or size might be different. 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. >From af323998a63a72f569d543cf5167d5d28e784682 Mon Sep 17 00:00:00 2001 From: Dinar Temirbulatov <dinar.temirbula...@arm.com> Date: Mon, 29 Jan 2024 14:43:13 +0000 Subject: [PATCH] [Clang][AArch64] Warn when calling streaming/non-streaming about vector size might be different. 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. --- .../clang/Basic/DiagnosticSemaKinds.td | 24 +++++++ clang/lib/Sema/SemaChecking.cpp | 42 ++++++++++++ clang/test/Sema/aarch64-sme-func-attrs.c | 68 ++++++++++++++++++- 3 files changed, 132 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 24d32cb87c89e2..37fea5746936c7 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3717,6 +3717,30 @@ def err_sme_definition_using_za_in_non_sme_target : Error< "function using ZA state requires 'sme'">; def err_sme_definition_using_zt0_in_non_sme2_target : Error< "function using ZT0 state requires 'sme2'">; +def warn_sme_streaming_caller_pass_args_to_non_streaming : Warning< + "streaming caller passes a VL-dependent argument to non-streaming callee, " + "the streaming and non-streaming vector lengths may be different">, + InGroup<IgnoredAttributes>; +def warn_sme_non_streaming_callee_returns_to_streaming : Warning< + "non-streaming callee returns a VL-dependent value to streaming caller, " + "the streaming and non-streaming vector lengths may be different">, + InGroup<IgnoredAttributes>; +def warn_sme_non_streaming_caller_pass_args_to_streaming : Warning< + "non-streaming caller passes a VL-dependent argument to streaming callee, " + "the streaming and non-streaming vector lengths may be different">, + InGroup<IgnoredAttributes>; +def warn_sme_non_streaming_caller_returns_to_streaming : Warning< + "non-streaming callee returns a VL-dependent value to streaming caller, " + "the streaming and non-streaming vector lengths may be different">, + InGroup<IgnoredAttributes>; +def warn_sme_locally_streaming_has_vl_args : Warning< + "non-streaming callee receives a VL-dependent argument and the callee has an arm_locally_streaming attribute, " + "the streaming and non-streaming vector lengths may be different">, + InGroup<IgnoredAttributes>; +def warn_sme_locally_streaming_returns_vl : Warning< + "non-streaming callee returns a VL-dependent value and the callee has an arm_locally_streaming attribute, " + "the streaming and non-streaming vector lengths may be different">, + InGroup<IgnoredAttributes>; def err_conflicting_attributes_arm_state : Error< "conflicting attributes for state '%0'">; def err_unknown_arm_state : Error< diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 502b24bcdf8b42..e668a45c69e5f9 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -7480,6 +7480,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, // For variadic functions, we may have more args than parameters. // For some K&R functions, we may have less args than parameters. const auto N = std::min<unsigned>(Proto->getNumParams(), Args.size()); + bool AnyScalableArgs = false; for (unsigned ArgIdx = 0; ArgIdx < N; ++ArgIdx) { // Args[ArgIdx] can be null in malformed code. if (const Expr *Arg = Args[ArgIdx]) { @@ -7493,6 +7494,8 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, checkAIXMemberAlignment((Arg->getExprLoc()), Arg); QualType ParamTy = Proto->getParamType(ArgIdx); + if (ParamTy->isSizelessVectorType()) + AnyScalableArgs = true; QualType ArgTy = Arg->getType(); CheckArgAlignment(Arg->getExprLoc(), FDecl, std::to_string(ArgIdx + 1), ArgTy, ParamTy); @@ -7513,6 +7516,45 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, } } + auto *CallerFD = dyn_cast<FunctionDecl>(CurContext); + if (FD && CallerFD && Context.getTargetInfo().hasFeature("sme") && + !FD->getBuiltinID()) { + // If the callee has an AArch64 SME __arm_locally_streaming attribute + // warn if this function returns VL-based value or pass any such argument, + // the streaming and non-streaming vector lengths may be different. + ArmStreamingType CalleeFnType = getArmStreamingFnType(FD); + ArmStreamingType CallerFnType = getArmStreamingFnType(CallerFD); + if (FD->hasAttr<ArmLocallyStreamingAttr>() && + CallerFnType != ArmStreaming) { + if (AnyScalableArgs) + Diag(Loc, diag::warn_sme_locally_streaming_has_vl_args); + if (FD->getReturnType()->isSizelessVectorType()) + Diag(Loc, diag::warn_sme_locally_streaming_returns_vl); + } + // If the caller is a non-streaming function and the callee has a + // streaming attribute. If it passed any VL-based arguments or return + // VL-based value, then warn that the streaming and non-streaming vector + // lengths may be different. + if (CallerFnType != ArmStreaming) { + if (CalleeFnType == ArmStreaming) { + if (AnyScalableArgs) + Diag(Loc, + diag::warn_sme_non_streaming_caller_pass_args_to_streaming); + if (FD->getReturnType()->isSizelessVectorType()) + Diag(Loc, diag::warn_sme_non_streaming_caller_returns_to_streaming); + } + } else if (!FD->hasAttr<ArmLocallyStreamingAttr>()) { + // If the callee is a non-streaming function and the caller has + // streaming attribute. If it passed any VL-based arguments or return + // VL-based value, then warn that the streaming and non-streaming vector + // lengths may be different. + if (AnyScalableArgs) + Diag(Loc, diag::warn_sme_streaming_caller_pass_args_to_non_streaming); + if (FD->getReturnType()->isSizelessVectorType()) + Diag(Loc, diag::warn_sme_non_streaming_callee_returns_to_streaming); + } + } + // If the callee uses AArch64 SME ZA state but the caller doesn't define // any, then this is an error. FunctionType::ArmStateValue ArmZAState = diff --git a/clang/test/Sema/aarch64-sme-func-attrs.c b/clang/test/Sema/aarch64-sme-func-attrs.c index 97409ae7d6040c..0a8e6e03a94f29 100644 --- a/clang/test/Sema/aarch64-sme-func-attrs.c +++ b/clang/test/Sema/aarch64-sme-func-attrs.c @@ -1,5 +1,6 @@ -// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -fsyntax-only -verify %s -// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -fsyntax-only -verify=expected-cpp -x c++ %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -fsyntax-only -verify=expected-cpp -x c++ %s +#include <arm_sme.h> // Valid attributes @@ -48,6 +49,9 @@ typedef void (*fptrty6) (void); fptrty6 cast_nza_func_to_normal() { return sme_arm_new_za; } fptrty6 cast_ls_func_to_normal() { return sme_arm_locally_streaming; } +void sme_arm_streaming_with_vl_args(void) __arm_streaming; + + // Invalid attributes // expected-cpp-error@+4 {{'__arm_streaming_compatible' and '__arm_streaming' are not compatible}} @@ -445,3 +449,63 @@ void conflicting_state_attrs_preserves_out_zt0(void) __arm_preserves("zt0") __ar // expected-cpp-error@+2 {{conflicting attributes for state 'zt0'}} // expected-error@+1 {{conflicting attributes for state 'zt0'}} void conflicting_state_attrs_preserves_inout_zt0(void) __arm_preserves("zt0") __arm_inout("zt0"); + +void sme_streaming_with_vl_arg(svint32x4_t a) __arm_streaming { } + +svint32x4_t sme_streaming_returns_vl(void) __arm_streaming { svint32x4_t r; return r; } + +void sme_none_streaming_with_vl_arg(svint32x4_t a) { } + +svint32x4_t sme_none_streaming_returns_vl(void) { svint32x4_t r; return r; } + +__arm_locally_streaming void sme_locally_streaming_with_vl_arg(svint32x4_t a) { } + +__arm_locally_streaming svint32x4_t sme_locally_streaming_returns_vl(void) { svint32x4_t r; return r; } + +void sme_none_streaming_calling_streaming_with_vl_args() { + svint32x4_t a; + // expected-warning@+2 {{non-streaming caller passes a VL-dependent argument to streaming callee, the streaming and non-streaming vector lengths may be different}} + // expected-cpp-warning@+1 {{non-streaming caller passes a VL-dependent argument to streaming callee, the streaming and non-streaming vector lengths may be different}} + sme_streaming_with_vl_arg(a); +} + +void sme_none_streaming_calling_streaming_with_return_vl() { + // expected-warning@+2 {{non-streaming callee returns a VL-dependent value to streaming caller, the streaming and non-streaming vector lengths may be different}} + // expected-cpp-warning@+1 {{non-streaming callee returns a VL-dependent value to streaming caller, the streaming and non-streaming vector lengths may be different}} + svint32x4_t r = sme_streaming_returns_vl(); +} + +void sme_streaming_calling_non_streaming_with_vl_args(void) __arm_streaming { + svint32x4_t a; + // expected-warning@+2 {{streaming caller passes a VL-dependent argument to non-streaming callee, the streaming and non-streaming vector lengths may be different}} + // expected-cpp-warning@+1 {{streaming caller passes a VL-dependent argument to non-streaming callee, the streaming and non-streaming vector lengths may be different}} + sme_none_streaming_with_vl_arg(a); +} + +void sme_streaming_calling_non_streaming_with_return_vl(void) __arm_streaming { + // expected-warning@+2 {{non-streaming callee returns a VL-dependent value to streaming caller, the streaming and non-streaming vector lengths may be different}} + // expected-cpp-warning@+1 {{non-streaming callee returns a VL-dependent value to streaming caller, the streaming and non-streaming vector lengths may be different}} + svint32x4_t r = sme_streaming_returns_vl(); +} + +void sme_streaming_calling_locally_streaming_with_vl_args(void) __arm_streaming { + svint32x4_t a; + // expected-1warning@+2 {{non-streaming callee receives a VL-dependent argument and the callee has an arm_locally_streaming attribute, the streaming and non-streaming vector lengths may be different}} + // expected-1cpp-warning@+1 {{non-streaming callee receives a VL-dependent argument and the callee has an arm_locally_streaming attribute, the streaming and non-streaming vector lengths may be different}} + sme_locally_streaming_with_vl_arg(a); +} + +void sme_streaming_calling_locally_streaming_with_return_vl(void) __arm_streaming { + // expected-1warning@+2 {{non-streaming callee returns a VL-dependent value and the callee has an arm_locally_streaming attribute, the streaming and non-streaming vector lengths may be different}} + // expected-1cpp-warning@+1 {{non-streaming callee returns a VL-dependent value and the callee has an arm_locally_streaming attribute, the streaming and non-streaming vector lengths may be different}} + svint32x4_t r = sme_locally_streaming_returns_vl(); +} + +void sme_none_streaming_calling_locally_streaming_with_vl_args(void) __arm_streaming { + svint32x4_t a; + sme_locally_streaming_with_vl_arg(a); +} + +void sme_none_streaming_calling_locally_streaming_with_return_vl(void) __arm_streaming { + svint32x4_t r = sme_locally_streaming_returns_vl(); +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits