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

Dinar Temirbulatov via cfe-commits cfe-commits at lists.llvm.org
Mon Jan 29 06:50:11 PST 2024


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.Temirbulatov at 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 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();
+}



More information about the cfe-commits mailing list