[clang] [Clang][AArch64] Warn when calling streaming/non-streaming about vect… (PR #79842)

Dinar Temirbulatov via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 15 04:17:21 PST 2024


https://github.com/dtemirbulatov updated https://github.com/llvm/llvm-project/pull/79842

>From af323998a63a72f569d543cf5167d5d28e784682 Mon Sep 17 00:00:00 2001
From: Dinar Temirbulatov <Dinar.Temirbulatov at arm.com>
Date: Mon, 29 Jan 2024 14:43:13 +0000
Subject: [PATCH 1/7] [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 at +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 at +2 {{conflicting attributes for state 'zt0'}}
 // expected-error at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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();
+}

>From 470777a7704353fbf81a61a5c2c5572e9928ce61 Mon Sep 17 00:00:00 2001
From: Dinar Temirbulatov <Dinar.Temirbulatov at arm.com>
Date: Tue, 30 Jan 2024 08:59:36 +0000
Subject: [PATCH 2/7] Corrected diagnostics, allowed to emit warning even when
 we call streaming local function from streaming function.

---
 clang/lib/Sema/SemaChecking.cpp          |  3 +--
 clang/test/Sema/aarch64-sme-func-attrs.c | 12 ++++++++----
 2 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index e668a45c69e5f9..5f7044cb09f80d 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -7524,8 +7524,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
       // 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 (FD->hasAttr<ArmLocallyStreamingAttr>()) {
         if (AnyScalableArgs)
           Diag(Loc, diag::warn_sme_locally_streaming_has_vl_args);
         if (FD->getReturnType()->isSizelessVectorType())
diff --git a/clang/test/Sema/aarch64-sme-func-attrs.c b/clang/test/Sema/aarch64-sme-func-attrs.c
index 0a8e6e03a94f29..05a0eead96d213 100644
--- a/clang/test/Sema/aarch64-sme-func-attrs.c
+++ b/clang/test/Sema/aarch64-sme-func-attrs.c
@@ -490,22 +490,26 @@ void sme_streaming_calling_non_streaming_with_return_vl(void) __arm_streaming {
 
 void sme_streaming_calling_locally_streaming_with_vl_args(void) __arm_streaming {
   svint32x4_t a;
-  // expected-1warning at +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 at +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}}
+  // expected-warning at +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-cpp-warning at +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 at +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 at +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}}
+  // expected-warning at +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-cpp-warning at +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;
+  // expected-warning at +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-cpp-warning at +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_none_streaming_calling_locally_streaming_with_return_vl(void) __arm_streaming {
+  // expected-warning at +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-cpp-warning at +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();
 }

>From 540a14782fd868d2b63555c2ae614a6b3e95674d Mon Sep 17 00:00:00 2001
From: Dinar Temirbulatov <Dinar.Temirbulatov at arm.com>
Date: Thu, 8 Feb 2024 07:44:47 +0000
Subject: [PATCH 3/7] Resolved comments.

---
 clang/lib/Sema/SemaChecking.cpp               |  8 +--
 clang/lib/Sema/SemaDecl.cpp                   | 16 ++++++
 .../Sema/aarch64-incompat-sm-builtin-calls.c  |  8 +++
 clang/test/Sema/aarch64-sme-func-attrs.c      | 56 +++++++------------
 4 files changed, 46 insertions(+), 42 deletions(-)

diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 5f7044cb09f80d..1414763fc97c1e 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -7524,12 +7524,6 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
       // the streaming and non-streaming vector lengths may be different.
       ArmStreamingType CalleeFnType = getArmStreamingFnType(FD);
       ArmStreamingType CallerFnType = getArmStreamingFnType(CallerFD);
-      if (FD->hasAttr<ArmLocallyStreamingAttr>()) {
-        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
@@ -7542,7 +7536,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
           if (FD->getReturnType()->isSizelessVectorType())
             Diag(Loc, diag::warn_sme_non_streaming_caller_returns_to_streaming);
         }
-      } else if (!FD->hasAttr<ArmLocallyStreamingAttr>()) {
+      } else if (CalleeFnType != ArmStreaming) {
         // 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
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index e725e187fc9ea0..0acb8e82b71e71 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -12236,6 +12236,22 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
     bool UsesSM = NewFD->hasAttr<ArmLocallyStreamingAttr>();
     bool UsesZA = Attr && Attr->isNewZA();
     bool UsesZT0 = Attr && Attr->isNewZT0();
+
+    if (UsesSM) {
+      if (NewFD->getReturnType()->isSizelessVectorType())
+        Diag(NewFD->getLocation(), diag::warn_sme_locally_streaming_returns_vl);
+      auto *FPT = NewFD->getType()->castAs<FunctionProtoType>();
+      bool AnyScalableArgs = false;
+      for (QualType T : FPT->param_types()) {
+        if (T->isSizelessVectorType()) {
+          AnyScalableArgs = true;
+          break;
+        }
+      }
+      if (AnyScalableArgs)
+        Diag(NewFD->getLocation(),
+             diag::warn_sme_locally_streaming_has_vl_args);
+    }
     if (const auto *FPT = NewFD->getType()->getAs<FunctionProtoType>()) {
       FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
       UsesSM |=
diff --git a/clang/test/Sema/aarch64-incompat-sm-builtin-calls.c b/clang/test/Sema/aarch64-incompat-sm-builtin-calls.c
index 55c97c73e8b695..83f61523927bc3 100644
--- a/clang/test/Sema/aarch64-incompat-sm-builtin-calls.c
+++ b/clang/test/Sema/aarch64-incompat-sm-builtin-calls.c
@@ -33,6 +33,8 @@ svuint32_t incompat_sve_sm(svbool_t pg, svuint32_t a, int16_t b) __arm_streaming
   return __builtin_sve_svld1_gather_u32base_index_u32(pg, a, b);
 }
 
+// expected-warning at +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-warning at +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}}
 __arm_locally_streaming svuint32_t incompat_sve_ls(svbool_t pg, svuint32_t a, int64_t b) {
   // expected-warning at +1 {{builtin call has undefined behaviour when called from a streaming function}}
   return __builtin_sve_svld1_gather_u32base_index_u32(pg, a, b);
@@ -48,6 +50,8 @@ svuint32_t incompat_sve2_sm(svbool_t pg, svuint32_t a, int64_t b) __arm_streamin
   return __builtin_sve_svldnt1_gather_u32base_index_u32(pg, a, b);
 }
 
+// expected-warning at +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-warning at +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}}
 __arm_locally_streaming svuint32_t incompat_sve2_ls(svbool_t pg, svuint32_t a, int64_t b) {
   // expected-warning at +1 {{builtin call has undefined behaviour when called from a streaming function}}
   return __builtin_sve_svldnt1_gather_u32base_index_u32(pg, a, b);
@@ -68,6 +72,8 @@ svfloat64_t streaming_caller_sve(svbool_t pg, svfloat64_t a, float64_t b) __arm_
   return svadd_n_f64_m(pg, a, b);
 }
 
+// expected-warning at +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-warning at +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}}
 __arm_locally_streaming svfloat64_t locally_streaming_caller_sve(svbool_t pg, svfloat64_t a, float64_t b) {
   // expected-no-warning
   return svadd_n_f64_m(pg, a, b);
@@ -83,6 +89,8 @@ svint16_t streaming_caller_sve2(svint16_t op1, svint16_t op2) __arm_streaming {
   return svmul_lane_s16(op1, op2, 0);
 }
 
+// expected-warning at +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-warning at +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}}
 __arm_locally_streaming svint16_t locally_streaming_caller_sve2(svint16_t op1, svint16_t op2) {
   // expected-no-warning
   return svmul_lane_s16(op1, op2, 0);
diff --git a/clang/test/Sema/aarch64-sme-func-attrs.c b/clang/test/Sema/aarch64-sme-func-attrs.c
index 05a0eead96d213..f54cad2eee967b 100644
--- a/clang/test/Sema/aarch64-sme-func-attrs.c
+++ b/clang/test/Sema/aarch64-sme-func-attrs.c
@@ -1,6 +1,5 @@
-// 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>
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sve -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sve -fsyntax-only -verify=expected-cpp -x c++ %s
 
 // Valid attributes
 
@@ -450,20 +449,24 @@ void conflicting_state_attrs_preserves_out_zt0(void) __arm_preserves("zt0") __ar
 // expected-error at +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 { }
+void sme_streaming_with_vl_arg(__SVInt8_t a) __arm_streaming { }
 
-svint32x4_t sme_streaming_returns_vl(void) __arm_streaming { svint32x4_t r; return r; }
+__SVInt8_t sme_streaming_returns_vl(void) __arm_streaming { __SVInt8_t r; return r; }
 
-void sme_none_streaming_with_vl_arg(svint32x4_t a) { }
+void sme_none_streaming_with_vl_arg(__SVInt8_t a) { }
 
-svint32x4_t sme_none_streaming_returns_vl(void) { svint32x4_t r; return r; }
+__SVInt8_t sme_none_streaming_returns_vl(void) { __SVInt8_t r; return r; }
 
-__arm_locally_streaming void sme_locally_streaming_with_vl_arg(svint32x4_t a) { }
+// expected-warning at +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-cpp-warning at +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}}
+__arm_locally_streaming void sme_locally_streaming_with_vl_arg(__SVInt8_t a) { }
 
-__arm_locally_streaming svint32x4_t sme_locally_streaming_returns_vl(void) { svint32x4_t r; return r; }
+// expected-warning at +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-cpp-warning at +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}}
+__arm_locally_streaming __SVInt8_t sme_locally_streaming_returns_vl(void) { __SVInt8_t r; return r; }
 
 void sme_none_streaming_calling_streaming_with_vl_args() {
-  svint32x4_t a;
+  __SVInt8_t a;
   // expected-warning at +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 at +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);
@@ -472,11 +475,11 @@ void sme_none_streaming_calling_streaming_with_vl_args() {
 void sme_none_streaming_calling_streaming_with_return_vl() {
   // expected-warning at +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 at +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();
+  __SVInt8_t r = sme_streaming_returns_vl();
 }
 
 void sme_streaming_calling_non_streaming_with_vl_args(void) __arm_streaming {
-  svint32x4_t a;
+  __SVInt8_t a;
   // expected-warning at +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 at +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);
@@ -485,31 +488,14 @@ void sme_streaming_calling_non_streaming_with_vl_args(void) __arm_streaming {
 void sme_streaming_calling_non_streaming_with_return_vl(void) __arm_streaming {
   // expected-warning at +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 at +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-warning at +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-cpp-warning at +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);
+  __SVInt8_t r = sme_none_streaming_returns_vl();
 }
 
-void sme_streaming_calling_locally_streaming_with_return_vl(void) __arm_streaming {
-  // expected-warning at +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-cpp-warning at +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;
-  // expected-warning at +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-cpp-warning at +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_streaming_with_vl_args(void) __arm_streaming {
+  __SVInt8_t a;
+  sme_streaming_with_vl_arg(a);
 }
 
-void sme_none_streaming_calling_locally_streaming_with_return_vl(void) __arm_streaming {
-  // expected-warning at +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-cpp-warning at +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_streaming_calling_streaming_with_return_vl(void) __arm_streaming {
+  __SVInt8_t r = sme_streaming_returns_vl();
 }

>From 790afb23fca64f59f8672d7e6d6bf08bec08c234 Mon Sep 17 00:00:00 2001
From: Dinar Temirbulatov <Dinar.Temirbulatov at arm.com>
Date: Thu, 8 Feb 2024 11:37:26 +0000
Subject: [PATCH 4/7] Add new waring group AArch64SMEAttributes.

---
 clang/include/clang/Basic/DiagnosticGroups.td    |  3 +++
 clang/include/clang/Basic/DiagnosticSemaKinds.td | 12 ++++++------
 2 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 6765721ae7002c..7f395a657046c0 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1390,6 +1390,9 @@ def MultiGPU: DiagGroup<"multi-gpu">;
 // libc and the CRT to be skipped.
 def AVRRtlibLinkingQuirks : DiagGroup<"avr-rtlib-linking-quirks">;
 
+// A warning group AArch64 related to SME function attribues.
+def AArch64SMEAttributes : DiagGroup<"aarch64-sme-attributes">;
+
 // A warning group for things that will change semantics in the future.
 def FutureCompat : DiagGroup<"future-compat">;
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 37fea5746936c7..03611e0c4531ad 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3720,27 +3720,27 @@ def err_sme_definition_using_zt0_in_non_sme2_target : Error<
 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>;
+  InGroup<AArch64SMEAttributes>;
 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>;
+  InGroup<AArch64SMEAttributes>;
 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>;
+  InGroup<AArch64SMEAttributes>;
 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>;
+  InGroup<AArch64SMEAttributes>;
 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>;
+  InGroup<AArch64SMEAttributes>;
 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>;
+  InGroup<AArch64SMEAttributes>;
 def err_conflicting_attributes_arm_state : Error<
   "conflicting attributes for state '%0'">;
 def err_unknown_arm_state : Error<

>From 66a37aa710ed6be7c3fd3ff46b6caf2adf688d65 Mon Sep 17 00:00:00 2001
From: Dinar Temirbulatov <Dinar.Temirbulatov at arm.com>
Date: Mon, 12 Feb 2024 18:45:38 +0000
Subject: [PATCH 5/7] Resolved comments.

---
 .../clang/Basic/DiagnosticSemaKinds.td        | 28 ++-----
 clang/lib/Sema/SemaChecking.cpp               | 27 +++---
 clang/lib/Sema/SemaDecl.cpp                   |  5 +-
 .../Sema/aarch64-incompat-sm-builtin-calls.c  | 16 ++--
 clang/test/Sema/aarch64-sme-func-attrs.c      | 83 ++++++++++++++-----
 5 files changed, 95 insertions(+), 64 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 03611e0c4531ad..a94692166f6460 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3717,29 +3717,13 @@ 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">,
+def warn_sme_streaming_pass_return_vl_to_non_streaming : Warning<
+  "passing a VL-dependent argument to/from a function that has a different"
+  " streaming-mode, is undefined behaviour">,
   InGroup<AArch64SMEAttributes>;
-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<AArch64SMEAttributes>;
-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<AArch64SMEAttributes>;
-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<AArch64SMEAttributes>;
-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<AArch64SMEAttributes>;
-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">,
+def warn_sme_locally_streaming_has_vl_args_returns : Warning<
+  "passing/returning a VL-dependent argument from a function"
+  " arm_locally_streaming attribute, is undefined behaviour">,
   InGroup<AArch64SMEAttributes>;
 def err_conflicting_attributes_arm_state : Error<
   "conflicting attributes for state '%0'">;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 1414763fc97c1e..95ac69d9ea90fd 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -7517,34 +7517,37 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
     }
 
     auto *CallerFD = dyn_cast<FunctionDecl>(CurContext);
-    if (FD && CallerFD && Context.getTargetInfo().hasFeature("sme") &&
-        !FD->getBuiltinID()) {
+    bool IsCalleeStreaming = ((ExtInfo.AArch64SMEAttributes &
+                               FunctionType::SME_PStateSMEnabledMask) ||
+                              (ExtInfo.AArch64SMEAttributes &
+                               FunctionType::SME_PStateSMCompatibleMask));
+    bool IsBuiltin = (FD && FD->getBuiltinID());
+
+    if (CallerFD && Context.getTargetInfo().hasFeature("sme") && !IsBuiltin) {
       // 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 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 (IsCalleeStreaming) {
           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);
+            Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming);
+          if (Proto->getReturnType()->isSizelessVectorType())
+            Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming);
         }
-      } else if (CalleeFnType != ArmStreaming) {
+      } else if (!IsCalleeStreaming) {
         // 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);
+          Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming);
+        if (Proto->getReturnType()->isSizelessVectorType())
+          Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming);
       }
     }
 
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 0acb8e82b71e71..355f464aa8f3f4 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -12239,7 +12239,8 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
 
     if (UsesSM) {
       if (NewFD->getReturnType()->isSizelessVectorType())
-        Diag(NewFD->getLocation(), diag::warn_sme_locally_streaming_returns_vl);
+        Diag(NewFD->getLocation(),
+             diag::warn_sme_locally_streaming_has_vl_args_returns);
       auto *FPT = NewFD->getType()->castAs<FunctionProtoType>();
       bool AnyScalableArgs = false;
       for (QualType T : FPT->param_types()) {
@@ -12250,7 +12251,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
       }
       if (AnyScalableArgs)
         Diag(NewFD->getLocation(),
-             diag::warn_sme_locally_streaming_has_vl_args);
+             diag::warn_sme_locally_streaming_has_vl_args_returns);
     }
     if (const auto *FPT = NewFD->getType()->getAs<FunctionProtoType>()) {
       FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
diff --git a/clang/test/Sema/aarch64-incompat-sm-builtin-calls.c b/clang/test/Sema/aarch64-incompat-sm-builtin-calls.c
index 83f61523927bc3..6002e9f25e2736 100644
--- a/clang/test/Sema/aarch64-incompat-sm-builtin-calls.c
+++ b/clang/test/Sema/aarch64-incompat-sm-builtin-calls.c
@@ -33,8 +33,8 @@ svuint32_t incompat_sve_sm(svbool_t pg, svuint32_t a, int16_t b) __arm_streaming
   return __builtin_sve_svld1_gather_u32base_index_u32(pg, a, b);
 }
 
-// expected-warning at +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-warning at +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}}
+// expected-warning at +2 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
+// expected-warning at +1 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
 __arm_locally_streaming svuint32_t incompat_sve_ls(svbool_t pg, svuint32_t a, int64_t b) {
   // expected-warning at +1 {{builtin call has undefined behaviour when called from a streaming function}}
   return __builtin_sve_svld1_gather_u32base_index_u32(pg, a, b);
@@ -50,8 +50,8 @@ svuint32_t incompat_sve2_sm(svbool_t pg, svuint32_t a, int64_t b) __arm_streamin
   return __builtin_sve_svldnt1_gather_u32base_index_u32(pg, a, b);
 }
 
-// expected-warning at +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-warning at +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}}
+// expected-warning at +2 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
+// expected-warning at +1 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
 __arm_locally_streaming svuint32_t incompat_sve2_ls(svbool_t pg, svuint32_t a, int64_t b) {
   // expected-warning at +1 {{builtin call has undefined behaviour when called from a streaming function}}
   return __builtin_sve_svldnt1_gather_u32base_index_u32(pg, a, b);
@@ -72,8 +72,8 @@ svfloat64_t streaming_caller_sve(svbool_t pg, svfloat64_t a, float64_t b) __arm_
   return svadd_n_f64_m(pg, a, b);
 }
 
-// expected-warning at +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-warning at +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}}
+// expected-warning at +2 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
+// expected-warning at +1 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
 __arm_locally_streaming svfloat64_t locally_streaming_caller_sve(svbool_t pg, svfloat64_t a, float64_t b) {
   // expected-no-warning
   return svadd_n_f64_m(pg, a, b);
@@ -89,8 +89,8 @@ svint16_t streaming_caller_sve2(svint16_t op1, svint16_t op2) __arm_streaming {
   return svmul_lane_s16(op1, op2, 0);
 }
 
-// expected-warning at +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-warning at +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}}
+// expected-warning at +2 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
+// expected-warning at +1 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
 __arm_locally_streaming svint16_t locally_streaming_caller_sve2(svint16_t op1, svint16_t op2) {
   // expected-no-warning
   return svmul_lane_s16(op1, op2, 0);
diff --git a/clang/test/Sema/aarch64-sme-func-attrs.c b/clang/test/Sema/aarch64-sme-func-attrs.c
index f54cad2eee967b..83c5776b93d170 100644
--- a/clang/test/Sema/aarch64-sme-func-attrs.c
+++ b/clang/test/Sema/aarch64-sme-func-attrs.c
@@ -453,49 +453,92 @@ void sme_streaming_with_vl_arg(__SVInt8_t a) __arm_streaming { }
 
 __SVInt8_t sme_streaming_returns_vl(void) __arm_streaming { __SVInt8_t r; return r; }
 
-void sme_none_streaming_with_vl_arg(__SVInt8_t a) { }
+void sme_streaming_compatible_with_vl_arg(__SVInt8_t a) __arm_streaming_compatible { }
 
-__SVInt8_t sme_none_streaming_returns_vl(void) { __SVInt8_t r; return r; }
+__SVInt8_t sme_streaming_compatible_returns_vl(void) __arm_streaming_compatible { __SVInt8_t r; return r; }
 
-// expected-warning at +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-cpp-warning at +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}}
+void sme_no_streaming_with_vl_arg(__SVInt8_t a) { }
+
+__SVInt8_t sme_no_streaming_returns_vl(void) { __SVInt8_t r; return r; }
+
+// expected-warning at +2 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
+// expected-cpp-warning at +1 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
 __arm_locally_streaming void sme_locally_streaming_with_vl_arg(__SVInt8_t a) { }
 
-// expected-warning at +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-cpp-warning at +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}}
+// expected-warning at +2 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
+// expected-cpp-warning at +1 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
 __arm_locally_streaming __SVInt8_t sme_locally_streaming_returns_vl(void) { __SVInt8_t r; return r; }
 
-void sme_none_streaming_calling_streaming_with_vl_args() {
+void sme_no_streaming_calling_streaming_with_vl_args() {
   __SVInt8_t a;
-  // expected-warning at +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 at +1 {{non-streaming caller passes a VL-dependent argument to streaming callee, the streaming and non-streaming vector lengths may be different}}
+  // expected-warning at +2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
+  // expected-cpp-warning at +1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
   sme_streaming_with_vl_arg(a);
 }
 
-void sme_none_streaming_calling_streaming_with_return_vl() {
-  // expected-warning at +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 at +1 {{non-streaming callee returns a VL-dependent value to streaming caller, the streaming and non-streaming vector lengths may be different}}
+void sme_no_streaming_calling_streaming_with_return_vl() {
+  // expected-warning at +2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
+  // expected-cpp-warning at +1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
   __SVInt8_t r = sme_streaming_returns_vl();
 }
 
 void sme_streaming_calling_non_streaming_with_vl_args(void) __arm_streaming {
   __SVInt8_t a;
-  // expected-warning at +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 at +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);
+  // expected-warning at +2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
+  // expected-cpp-warning at +1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
+  sme_no_streaming_with_vl_arg(a);
 }
 
 void sme_streaming_calling_non_streaming_with_return_vl(void) __arm_streaming {
-  // expected-warning at +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 at +1 {{non-streaming callee returns a VL-dependent value to streaming caller, the streaming and non-streaming vector lengths may be different}}
-  __SVInt8_t r = sme_none_streaming_returns_vl();
+  // expected-warning at +2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
+  // expected-cpp-warning at +1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
+  __SVInt8_t r = sme_no_streaming_returns_vl();
 }
 
-void sme_streaming_calling_streaming_with_vl_args(void) __arm_streaming {
-  __SVInt8_t a;
+void sme_no_streaming_calling_streaming(__SVInt8_t arg, void (*sc)( __SVInt8_t arg) __arm_streaming) {
+  // expected-warning at +2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
+  // expected-cpp-warning at +1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
+  sc(arg);
+}
+
+__SVInt8_t sme_no_streaming_calling_streaming_return_vl(__SVInt8_t (*sc)(void) __arm_streaming) {
+  // expected-warning at +2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
+  // expected-cpp-warning at +1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
+  return sc();
+}
+
+void sme_streaming_compatible_calling_streaming(__SVInt8_t arg) __arm_streaming_compatible {
+  // expected-warning at +2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
+  // expected-cpp-warning at +1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
+  sme_streaming_with_vl_arg(arg);
+}
+
+void sme_streaming_compatible_sme_streaming_compatible_return_vl(void) __arm_streaming_compatible {
+  // expected-warning at +2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
+  // expected-cpp-warning at +1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
+  __SVInt8_t r = sme_streaming_returns_vl();
+}
+
+void sme_streaming_calling_streaming(__SVInt8_t arg, void (*sc)( __SVInt8_t arg) __arm_streaming) __arm_streaming {
+  sc(arg);
+}
+
+__SVInt8_t sme_streaming_calling_streaming_return_vl(__SVInt8_t (*sc)(void) __arm_streaming) __arm_streaming {
+  return sc();
+}
+
+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();
+}

>From 1827ad66a1e4d40542d3a22dc3eb981a6ad1cd2a Mon Sep 17 00:00:00 2001
From: Dinar Temirbulatov <Dinar.Temirbulatov at arm.com>
Date: Thu, 15 Feb 2024 11:51:54 +0000
Subject: [PATCH 6/7] Resolve comments.

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  6 +-
 clang/lib/Sema/SemaChecking.cpp               | 49 +++++-----
 clang/lib/Sema/SemaDecl.cpp                   | 16 +---
 .../Sema/aarch64-incompat-sm-builtin-calls.c  | 12 +--
 clang/test/Sema/aarch64-sme-func-attrs.c      | 96 +++++++++++++------
 5 files changed, 101 insertions(+), 78 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index a94692166f6460..b60b5a6d379bc7 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3719,11 +3719,13 @@ def err_sme_definition_using_zt0_in_non_sme2_target : Error<
   "function using ZT0 state requires 'sme2'">;
 def warn_sme_streaming_pass_return_vl_to_non_streaming : Warning<
   "passing a VL-dependent argument to/from a function that has a different"
-  " streaming-mode, is undefined behaviour">,
+  " streaming-mode, the streaming and non-streaming vector lengths may be"
+  " different">,
   InGroup<AArch64SMEAttributes>;
 def warn_sme_locally_streaming_has_vl_args_returns : Warning<
   "passing/returning a VL-dependent argument from a function"
-  " arm_locally_streaming attribute, is undefined behaviour">,
+  " arm_locally_streaming attribute, the streaming and non-streaming vector"
+  " lengths may be different">,
   InGroup<AArch64SMEAttributes>;
 def err_conflicting_attributes_arm_state : Error<
   "conflicting attributes for state '%0'">;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 95ac69d9ea90fd..7b501fc1f289bc 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -7480,7 +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;
+    bool AnyScalableArgsOrRet = false;
     for (unsigned ArgIdx = 0; ArgIdx < N; ++ArgIdx) {
       // Args[ArgIdx] can be null in malformed code.
       if (const Expr *Arg = Args[ArgIdx]) {
@@ -7495,7 +7495,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
 
         QualType ParamTy = Proto->getParamType(ArgIdx);
         if (ParamTy->isSizelessVectorType())
-          AnyScalableArgs = true;
+          AnyScalableArgsOrRet = true;
         QualType ArgTy = Arg->getType();
         CheckArgAlignment(Arg->getExprLoc(), FDecl, std::to_string(ArgIdx + 1),
                           ArgTy, ParamTy);
@@ -7517,36 +7517,31 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
     }
 
     auto *CallerFD = dyn_cast<FunctionDecl>(CurContext);
-    bool IsCalleeStreaming = ((ExtInfo.AArch64SMEAttributes &
-                               FunctionType::SME_PStateSMEnabledMask) ||
-                              (ExtInfo.AArch64SMEAttributes &
-                               FunctionType::SME_PStateSMCompatibleMask));
+    bool IsCalleeStreaming =
+        (ExtInfo.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask);
+    bool IsCalleeStreamingCompatible =
+        (ExtInfo.AArch64SMEAttributes &
+         FunctionType::SME_PStateSMCompatibleMask);
     bool IsBuiltin = (FD && FD->getBuiltinID());
+    AnyScalableArgsOrRet |= Proto->getReturnType()->isSizelessVectorType();
 
+    // If the caller is a function and the callee has a different
+    // non-compitable 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 (CallerFD && Context.getTargetInfo().hasFeature("sme") && !IsBuiltin) {
-      // 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 CallerFnType = getArmStreamingFnType(CallerFD);
-      // 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 (IsCalleeStreaming) {
-          if (AnyScalableArgs)
-            Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming);
-          if (Proto->getReturnType()->isSizelessVectorType())
-            Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming);
-        }
-      } else if (!IsCalleeStreaming) {
-        // 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)
+      if (CallerFnType != ArmStreaming &&
+          CallerFnType != ArmStreamingCompatible) {
+        if (IsCalleeStreaming && AnyScalableArgsOrRet)
+          Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming);
+      } else if (CallerFnType == ArmStreaming && !IsCalleeStreaming &&
+                 !IsCalleeStreamingCompatible) {
+        if (AnyScalableArgsOrRet)
           Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming);
-        if (Proto->getReturnType()->isSizelessVectorType())
+      } else if (CallerFnType == ArmStreamingCompatible) {
+        if ((IsCalleeStreaming || !IsCalleeStreamingCompatible) &&
+            AnyScalableArgsOrRet)
           Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming);
       }
     }
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 355f464aa8f3f4..411616ff715544 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -12238,18 +12238,10 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
     bool UsesZT0 = Attr && Attr->isNewZT0();
 
     if (UsesSM) {
-      if (NewFD->getReturnType()->isSizelessVectorType())
-        Diag(NewFD->getLocation(),
-             diag::warn_sme_locally_streaming_has_vl_args_returns);
-      auto *FPT = NewFD->getType()->castAs<FunctionProtoType>();
-      bool AnyScalableArgs = false;
-      for (QualType T : FPT->param_types()) {
-        if (T->isSizelessVectorType()) {
-          AnyScalableArgs = true;
-          break;
-        }
-      }
-      if (AnyScalableArgs)
+      if (NewFD->getReturnType()->isSizelessVectorType() ||
+          llvm::any_of(NewFD->parameters(), [](ParmVarDecl *P) {
+            return P->getOriginalType()->isSizelessVectorType();
+          }))
         Diag(NewFD->getLocation(),
              diag::warn_sme_locally_streaming_has_vl_args_returns);
     }
diff --git a/clang/test/Sema/aarch64-incompat-sm-builtin-calls.c b/clang/test/Sema/aarch64-incompat-sm-builtin-calls.c
index 6002e9f25e2736..52ca11b3147c9c 100644
--- a/clang/test/Sema/aarch64-incompat-sm-builtin-calls.c
+++ b/clang/test/Sema/aarch64-incompat-sm-builtin-calls.c
@@ -33,8 +33,7 @@ svuint32_t incompat_sve_sm(svbool_t pg, svuint32_t a, int16_t b) __arm_streaming
   return __builtin_sve_svld1_gather_u32base_index_u32(pg, a, b);
 }
 
-// expected-warning at +2 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
-// expected-warning at +1 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
+// expected-warning at +1 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, the streaming and non-streaming vector lengths may be different}}
 __arm_locally_streaming svuint32_t incompat_sve_ls(svbool_t pg, svuint32_t a, int64_t b) {
   // expected-warning at +1 {{builtin call has undefined behaviour when called from a streaming function}}
   return __builtin_sve_svld1_gather_u32base_index_u32(pg, a, b);
@@ -50,8 +49,7 @@ svuint32_t incompat_sve2_sm(svbool_t pg, svuint32_t a, int64_t b) __arm_streamin
   return __builtin_sve_svldnt1_gather_u32base_index_u32(pg, a, b);
 }
 
-// expected-warning at +2 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
-// expected-warning at +1 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
+// expected-warning at +1 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, the streaming and non-streaming vector lengths may be different}}
 __arm_locally_streaming svuint32_t incompat_sve2_ls(svbool_t pg, svuint32_t a, int64_t b) {
   // expected-warning at +1 {{builtin call has undefined behaviour when called from a streaming function}}
   return __builtin_sve_svldnt1_gather_u32base_index_u32(pg, a, b);
@@ -72,8 +70,7 @@ svfloat64_t streaming_caller_sve(svbool_t pg, svfloat64_t a, float64_t b) __arm_
   return svadd_n_f64_m(pg, a, b);
 }
 
-// expected-warning at +2 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
-// expected-warning at +1 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
+// expected-warning at +1 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, the streaming and non-streaming vector lengths may be different}}
 __arm_locally_streaming svfloat64_t locally_streaming_caller_sve(svbool_t pg, svfloat64_t a, float64_t b) {
   // expected-no-warning
   return svadd_n_f64_m(pg, a, b);
@@ -89,8 +86,7 @@ svint16_t streaming_caller_sve2(svint16_t op1, svint16_t op2) __arm_streaming {
   return svmul_lane_s16(op1, op2, 0);
 }
 
-// expected-warning at +2 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
-// expected-warning at +1 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
+// expected-warning at +1 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, the streaming and non-streaming vector lengths may be different}}
 __arm_locally_streaming svint16_t locally_streaming_caller_sve2(svint16_t op1, svint16_t op2) {
   // expected-no-warning
   return svmul_lane_s16(op1, op2, 0);
diff --git a/clang/test/Sema/aarch64-sme-func-attrs.c b/clang/test/Sema/aarch64-sme-func-attrs.c
index 83c5776b93d170..88529fe7ef969d 100644
--- a/clang/test/Sema/aarch64-sme-func-attrs.c
+++ b/clang/test/Sema/aarch64-sme-func-attrs.c
@@ -461,70 +461,82 @@ void sme_no_streaming_with_vl_arg(__SVInt8_t a) { }
 
 __SVInt8_t sme_no_streaming_returns_vl(void) { __SVInt8_t r; return r; }
 
-// expected-warning at +2 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
-// expected-cpp-warning at +1 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
+// expected-warning at +2 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, the streaming and non-streaming vector lengths may be different}}
+// expected-cpp-warning at +1 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, the streaming and non-streaming vector lengths may be different}}
 __arm_locally_streaming void sme_locally_streaming_with_vl_arg(__SVInt8_t a) { }
 
-// expected-warning at +2 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
-// expected-cpp-warning at +1 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, is undefined behaviour}}
+// expected-warning at +2 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, the streaming and non-streaming vector lengths may be different}}
+// expected-cpp-warning at +1 {{passing/returning a VL-dependent argument from a function arm_locally_streaming attribute, the streaming and non-streaming vector lengths may be different}}
 __arm_locally_streaming __SVInt8_t sme_locally_streaming_returns_vl(void) { __SVInt8_t r; return r; }
 
 void sme_no_streaming_calling_streaming_with_vl_args() {
   __SVInt8_t a;
-  // expected-warning at +2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
-  // expected-cpp-warning at +1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
+  // expected-warning at +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}}
+  // expected-cpp-warning at +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}}
   sme_streaming_with_vl_arg(a);
 }
 
 void sme_no_streaming_calling_streaming_with_return_vl() {
-  // expected-warning at +2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
-  // expected-cpp-warning at +1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
+  // expected-warning at +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}}
+  // expected-cpp-warning at +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}}
   __SVInt8_t r = sme_streaming_returns_vl();
 }
 
 void sme_streaming_calling_non_streaming_with_vl_args(void) __arm_streaming {
   __SVInt8_t a;
-  // expected-warning at +2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
-  // expected-cpp-warning at +1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
+  // expected-warning at +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}}
+  // expected-cpp-warning at +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}}
   sme_no_streaming_with_vl_arg(a);
 }
 
 void sme_streaming_calling_non_streaming_with_return_vl(void) __arm_streaming {
-  // expected-warning at +2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
-  // expected-cpp-warning at +1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
+  // expected-warning at +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}}
+  // expected-cpp-warning at +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}}
   __SVInt8_t r = sme_no_streaming_returns_vl();
 }
 
-void sme_no_streaming_calling_streaming(__SVInt8_t arg, void (*sc)( __SVInt8_t arg) __arm_streaming) {
-  // expected-warning at +2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
-  // expected-cpp-warning at +1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
+void sme_no_streaming_calling_streaming_with_vl_args_param(__SVInt8_t arg, void (*sc)( __SVInt8_t arg) __arm_streaming) {
+  // expected-warning at +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}}
+  // expected-cpp-warning at +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}}
   sc(arg);
 }
 
-__SVInt8_t sme_no_streaming_calling_streaming_return_vl(__SVInt8_t (*sc)(void) __arm_streaming) {
-  // expected-warning at +2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
-  // expected-cpp-warning at +1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
-  return sc();
+__SVInt8_t sme_no_streaming_calling_streaming_return_vl_param(__SVInt8_t (*s)(void) __arm_streaming) {
+  // expected-warning at +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}}
+  // expected-cpp-warning at +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}}
+  return s();
 }
 
-void sme_streaming_compatible_calling_streaming(__SVInt8_t arg) __arm_streaming_compatible {
-  // expected-warning at +2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
-  // expected-cpp-warning at +1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
+void sme_streaming_compatible_calling_streaming_with_vl_args(__SVInt8_t arg) __arm_streaming_compatible {
+  // expected-warning at +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}}
+  // expected-cpp-warning at +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}}
   sme_streaming_with_vl_arg(arg);
 }
 
-void sme_streaming_compatible_sme_streaming_compatible_return_vl(void) __arm_streaming_compatible {
-  // expected-warning at +2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
-  // expected-cpp-warning at +1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour}}
+void sme_streaming_compatible_calling_sme_streaming_return_vl(void) __arm_streaming_compatible {
+  // expected-warning at +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}}
+  // expected-cpp-warning at +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}}
   __SVInt8_t r = sme_streaming_returns_vl();
 }
 
-void sme_streaming_calling_streaming(__SVInt8_t arg, void (*sc)( __SVInt8_t arg) __arm_streaming) __arm_streaming {
-  sc(arg);
+void sme_streaming_compatible_calling_no_streaming_with_vl_args(__SVInt8_t arg) __arm_streaming_compatible {
+  // expected-warning at +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}}
+  // expected-cpp-warning at +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}}
+  sme_no_streaming_with_vl_arg(arg);
+}
+
+void sme_streaming_compatible_calling_no_sme_streaming_return_vl(void) __arm_streaming_compatible {
+  // expected-warning at +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}}
+  // expected-cpp-warning at +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}}
+  __SVInt8_t r = sme_no_streaming_returns_vl();
 }
 
-__SVInt8_t sme_streaming_calling_streaming_return_vl(__SVInt8_t (*sc)(void) __arm_streaming) __arm_streaming {
-  return sc();
+void sme_streaming_calling_streaming(__SVInt8_t arg, void (*s)( __SVInt8_t arg) __arm_streaming) __arm_streaming {
+  s(arg);
+}
+
+__SVInt8_t sme_streaming_calling_streaming_return_vl(__SVInt8_t (*s)(void) __arm_streaming) __arm_streaming {
+  return s();
 }
 
 void sme_streaming_calling_streaming_with_vl_args(__SVInt8_t a) __arm_streaming {
@@ -542,3 +554,29 @@ void sme_streaming_calling_streaming_compatible_with_vl_args(__SVInt8_t a) __arm
 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_compatible_with_vl_args() {
+  __SVInt8_t a;
+  sme_no_streaming_with_vl_arg(a);
+}
+
+void sme_no_streaming_calling_non_streaming_compatible_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();
+}

>From e2a82ee38fab05ca12c416f3d37d2fad275a069a Mon Sep 17 00:00:00 2001
From: Dinar Temirbulatov <Dinar.Temirbulatov at arm.com>
Date: Thu, 15 Feb 2024 12:16:31 +0000
Subject: [PATCH 7/7] Updated comment in clang/lib/Sema/SemaDecl.cpp

---
 clang/lib/Sema/SemaDecl.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 411616ff715544..55152f3aca7f07 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -12230,7 +12230,8 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
   }
 
   // Check if the function definition uses any AArch64 SME features without
-  // having the '+sme' feature enabled.
+  // having the '+sme' feature enabled and warn user if sme locally streaming
+  // function returns or uses arguments with VL-based types.
   if (DeclIsDefn) {
     const auto *Attr = NewFD->getAttr<ArmNewAttr>();
     bool UsesSM = NewFD->hasAttr<ArmLocallyStreamingAttr>();



More information about the cfe-commits mailing list