diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 409a8202d8a09..302ad9846391c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3980,6 +3980,14 @@ def warn_sme_locally_streaming_has_vl_args_returns : Warning< "%select{returning|passing}0 a VL-dependent argument %select{from|to}0 a locally streaming function is undefined" " behaviour when the streaming and non-streaming vector lengths are different at runtime">, InGroup, DefaultIgnore; +def warn_sme_streaming_compatible_vl_mismatch : Warning< + "%select{returning|passing}0 a VL-dependent argument %select{from|to}0 a %select{non-streaming|streaming}1" + " function is undefined behaviour when the streaming-compatible caller is%select{| not}1 in streaming" + " mode, because the streaming vector length (%2 bit) and non-streaming vector length (%3 bit) differ">, + InGroup, DefaultIgnore; +def err_sme_streaming_transition_vl_mismatch : Error< + "%select{returning|passing}0 a VL-dependent argument %select{from|to}0 a function with a different" + " streaming-mode is undefined behaviour because the streaming vector length (%1 bit) and non-streaming vector length (%2 bit) differ">; def err_conflicting_attributes_arm_agnostic : Error< "__arm_agnostic(\"sme_za_state\") cannot share ZA state with its caller">; def err_conflicting_attributes_arm_state : Error< diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 05ee51913aec1..59b53ae020f74 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -3756,6 +3756,8 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, // If the call requires a streaming-mode change and has scalable vector // arguments or return values, then warn the user that the streaming and // non-streaming vector lengths may be different. + // When both streaming and non-streaming vector lengths are defined and + // mismatched, produce an error. const auto *CallerFD = dyn_cast(CurContext); if (CallerFD && (!FD || !FD->getBuiltinID()) && (IsScalableArg || IsScalableRet)) { @@ -3768,12 +3770,30 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, if (!IsCalleeStreamingCompatible && (CallerFnType == SemaARM::ArmStreamingCompatible || ((CallerFnType == SemaARM::ArmStreaming) ^ IsCalleeStreaming))) { + const LangOptions &LO = getLangOpts(); + unsigned VL = LO.VScaleMin * 128; + unsigned SVL = LO.VScaleStreamingMin * 128; + bool IsVLMismatch = VL && SVL && VL != SVL; + + auto EmitDiag = [&](bool IsArg) { + if (IsVLMismatch) { + if (CallerFnType == SemaARM::ArmStreamingCompatible) + // Emit warning for streaming-compatible callers + Diag(Loc, diag::warn_sme_streaming_compatible_vl_mismatch) + << IsArg << IsCalleeStreaming << SVL << VL; + else + // Emit error otherwise + Diag(Loc, diag::err_sme_streaming_transition_vl_mismatch) + << IsArg << SVL << VL; + } else + Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming) + << IsArg; + }; + if (IsScalableArg) - Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming) - << /*IsArg=*/true; + EmitDiag(true); if (IsScalableRet) - Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming) - << /*IsArg=*/false; + EmitDiag(false); } } diff --git a/clang/test/Sema/aarch64-sme-streaming-nonstreaming-vl-checks.c b/clang/test/Sema/aarch64-sme-streaming-nonstreaming-vl-checks.c new file mode 100644 index 0000000000000..41d89869062ff --- /dev/null +++ b/clang/test/Sema/aarch64-sme-streaming-nonstreaming-vl-checks.c @@ -0,0 +1,111 @@ +// Case 1: No vscale flags — should only produce warnings +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +bf16 -target-feature +sme -target-feature +sme2 -target-feature +sve -Waarch64-sme-attributes -fsyntax-only -verify=expected-noflags %s + +// Case 2: Explicit mismatch in vscale flags — should produce errors for +// streaming and non-streaming callers +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +bf16 -target-feature +sme -target-feature +sme2 -target-feature +sve -Waarch64-sme-attributes -fsyntax-only -mvscale-min=1 -mvscale-max=1 -mvscale-streaming-min=2 -mvscale-streaming-max=2 -verify=expected-flags %s + +void sme_streaming_with_vl_arg(__SVInt8_t a) __arm_streaming; + +__SVInt8_t sme_streaming_returns_vl(void) __arm_streaming; + +void sme_streaming_compatible_with_vl_arg(__SVInt8_t a) __arm_streaming_compatible; + +__SVInt8_t sme_streaming_compatible_returns_vl(void) __arm_streaming_compatible; + +void sme_no_streaming_with_vl_arg(__SVInt8_t a); + +__SVInt8_t sme_no_streaming_returns_vl(void); + + +void sme_no_streaming_calling_streaming_with_vl_args() { + __SVInt8_t a; + // expected-noflags-warning@+2 {{passing a VL-dependent argument to a function with a different streaming-mode is undefined behaviour when the streaming and non-streaming vector lengths are different at runtime}} + // expected-flags-error@+1 {{passing a VL-dependent argument to a function with a different streaming-mode is undefined behaviour because the streaming vector length (256 bit) and non-streaming vector length (128 bit) differ}} + sme_streaming_with_vl_arg(a); +} + +void sme_no_streaming_calling_streaming_with_return_vl() { + // expected-noflags-warning@+2 {{returning a VL-dependent argument from a function with a different streaming-mode is undefined behaviour when the streaming and non-streaming vector lengths are different at runtime}} + // expected-flags-error@+1 {{returning a VL-dependent argument from a function with a different streaming-mode is undefined behaviour because the streaming vector length (256 bit) and non-streaming vector length (128 bit) differ}} + __SVInt8_t r = sme_streaming_returns_vl(); +} + +void sme_streaming_calling_non_streaming_with_vl_args(void) __arm_streaming { + __SVInt8_t a; + // expected-noflags-warning@+2 {{passing a VL-dependent argument to a function with a different streaming-mode is undefined behaviour when the streaming and non-streaming vector lengths are different at runtime}} + // expected-flags-error@+1 {{passing a VL-dependent argument to a function with a different streaming-mode is undefined behaviour because the streaming vector length (256 bit) and non-streaming vector length (128 bit) differ}} + sme_no_streaming_with_vl_arg(a); +} + +void sme_streaming_calling_non_streaming_with_return_vl(void) __arm_streaming { + // expected-noflags-warning@+2 {{returning a VL-dependent argument from a function with a different streaming-mode is undefined behaviour when the streaming and non-streaming vector lengths are different at runtime}} + // expected-flags-error@+1 {{returning a VL-dependent argument from a function with a different streaming-mode is undefined behaviour because the streaming vector length (256 bit) and non-streaming vector length (128 bit) differ}} + __SVInt8_t r = sme_no_streaming_returns_vl(); +} + +void sme_streaming_compatible_calling_streaming_with_vl_args(__SVInt8_t arg) __arm_streaming_compatible { + // expected-noflags-warning@+2 {{passing a VL-dependent argument to a function with a different streaming-mode is undefined behaviour when the streaming and non-streaming vector lengths are different at runtime}} + // expected-flags-warning@+1 {{passing a VL-dependent argument to a streaming function is undefined behaviour when the streaming-compatible caller is not in streaming mode, because the streaming vector length (256 bit) and non-streaming vector length (128 bit) differ}} + sme_streaming_with_vl_arg(arg); +} + +void sme_streaming_compatible_calling_sme_streaming_return_vl(void) __arm_streaming_compatible { + // expected-noflags-warning@+2 {{returning a VL-dependent argument from a function with a different streaming-mode is undefined behaviour when the streaming and non-streaming vector lengths are different at runtime}} + // expected-flags-warning@+1 {{returning a VL-dependent argument from a streaming function is undefined behaviour when the streaming-compatible caller is not in streaming mode, because the streaming vector length (256 bit) and non-streaming vector length (128 bit) differ}} + __SVInt8_t r = sme_streaming_returns_vl(); +} + +void sme_streaming_compatible_calling_no_streaming_with_vl_args(__SVInt8_t arg) __arm_streaming_compatible { + // expected-noflags-warning@+2 {{passing a VL-dependent argument to a function with a different streaming-mode is undefined behaviour when the streaming and non-streaming vector lengths are different at runtime}} + // expected-flags-warning@+1 {{passing a VL-dependent argument to a non-streaming function is undefined behaviour when the streaming-compatible caller is in streaming mode, because the streaming vector length (256 bit) and non-streaming vector length (128 bit) differ}} + sme_no_streaming_with_vl_arg(arg); +} + +void sme_streaming_compatible_calling_no_sme_streaming_return_vl(void) __arm_streaming_compatible { + // expected-noflags-warning@+2 {{returning a VL-dependent argument from a function with a different streaming-mode is undefined behaviour when the streaming and non-streaming vector lengths are different at runtime}} + // expected-flags-warning@+1 {{returning a VL-dependent argument from a non-streaming function is undefined behaviour when the streaming-compatible caller is in streaming mode, because the streaming vector length (256 bit) and non-streaming vector length (128 bit) differ}} + __SVInt8_t r = sme_no_streaming_returns_vl(); +} + +void sme_streaming_calling_streaming_with_vl_args(__SVInt8_t a) __arm_streaming { + sme_streaming_with_vl_arg(a); +} + +void sme_streaming_calling_streaming_with_return_vl(void) __arm_streaming { + __SVInt8_t r = sme_streaming_returns_vl(); +} + +void sme_streaming_calling_streaming_compatible_with_vl_args(__SVInt8_t a) __arm_streaming { + sme_streaming_compatible_with_vl_arg(a); +} + +void sme_streaming_calling_streaming_compatible_with_return_vl(void) __arm_streaming { + __SVInt8_t r = sme_streaming_compatible_returns_vl(); +} + +void sme_no_streaming_calling_streaming_compatible_with_vl_args() { + __SVInt8_t a; + sme_streaming_compatible_with_vl_arg(a); +} + +void sme_no_streaming_calling_streaming_compatible_with_return_vl() { + __SVInt8_t r = sme_streaming_compatible_returns_vl(); +} + +void sme_no_streaming_calling_non_streaming_with_vl_args() { + __SVInt8_t a; + sme_no_streaming_with_vl_arg(a); +} + +void sme_no_streaming_calling_non_streaming_with_return_vl() { + __SVInt8_t r = sme_no_streaming_returns_vl(); +} + +void sme_streaming_compatible_calling_streaming_compatible_with_vl_args(__SVInt8_t arg) __arm_streaming_compatible { + sme_streaming_compatible_with_vl_arg(arg); +} + +void sme_streaming_compatible_calling_streaming_compatible_with_return_vl(void) __arm_streaming_compatible { + __SVInt8_t r = sme_streaming_compatible_returns_vl(); +}