-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[Clang][AArch64] Warn when calling streaming/non-streaming about vect… #79842
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-clang Author: Dinar Temirbulatov (dtemirbulatov) Changes…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. Full diff: https://github.com/llvm/llvm-project/pull/79842.diff 3 Files Affected:
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 24d32cb87c89e24..37fea5746936c7a 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 502b24bcdf8b42b..e668a45c69e5f91 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 97409ae7d6040c0..0a8e6e03a94f291 100644
--- a/clang/test/Sema/aarch64-sme-func-attrs.c
+++ b/clang/test/Sema/aarch64-sme-func-attrs.c
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -fsyntax-only -verify %s
-// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -fsyntax-only -verify=expected-cpp -x c++ %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +sme -fsyntax-only -verify=expected-cpp -x c++ %s
+#include <arm_sme.h>
// Valid attributes
@@ -48,6 +49,9 @@ typedef void (*fptrty6) (void);
fptrty6 cast_nza_func_to_normal() { return sme_arm_new_za; }
fptrty6 cast_ls_func_to_normal() { return sme_arm_locally_streaming; }
+void sme_arm_streaming_with_vl_args(void) __arm_streaming;
+
+
// Invalid attributes
// expected-cpp-error@+4 {{'__arm_streaming_compatible' and '__arm_streaming' are not compatible}}
@@ -445,3 +449,63 @@ void conflicting_state_attrs_preserves_out_zt0(void) __arm_preserves("zt0") __ar
// expected-cpp-error@+2 {{conflicting attributes for state 'zt0'}}
// expected-error@+1 {{conflicting attributes for state 'zt0'}}
void conflicting_state_attrs_preserves_inout_zt0(void) __arm_preserves("zt0") __arm_inout("zt0");
+
+void sme_streaming_with_vl_arg(svint32x4_t a) __arm_streaming { }
+
+svint32x4_t sme_streaming_returns_vl(void) __arm_streaming { svint32x4_t r; return r; }
+
+void sme_none_streaming_with_vl_arg(svint32x4_t a) { }
+
+svint32x4_t sme_none_streaming_returns_vl(void) { svint32x4_t r; return r; }
+
+__arm_locally_streaming void sme_locally_streaming_with_vl_arg(svint32x4_t a) { }
+
+__arm_locally_streaming svint32x4_t sme_locally_streaming_returns_vl(void) { svint32x4_t r; return r; }
+
+void sme_none_streaming_calling_streaming_with_vl_args() {
+ svint32x4_t a;
+ // expected-warning@+2 {{non-streaming caller passes a VL-dependent argument to streaming callee, the streaming and non-streaming vector lengths may be different}}
+ // expected-cpp-warning@+1 {{non-streaming caller passes a VL-dependent argument to streaming callee, the streaming and non-streaming vector lengths may be different}}
+ sme_streaming_with_vl_arg(a);
+}
+
+void sme_none_streaming_calling_streaming_with_return_vl() {
+ // expected-warning@+2 {{non-streaming callee returns a VL-dependent value to streaming caller, the streaming and non-streaming vector lengths may be different}}
+ // expected-cpp-warning@+1 {{non-streaming callee returns a VL-dependent value to streaming caller, the streaming and non-streaming vector lengths may be different}}
+ svint32x4_t r = sme_streaming_returns_vl();
+}
+
+void sme_streaming_calling_non_streaming_with_vl_args(void) __arm_streaming {
+ svint32x4_t a;
+ // expected-warning@+2 {{streaming caller passes a VL-dependent argument to non-streaming callee, the streaming and non-streaming vector lengths may be different}}
+ // expected-cpp-warning@+1 {{streaming caller passes a VL-dependent argument to non-streaming callee, the streaming and non-streaming vector lengths may be different}}
+ sme_none_streaming_with_vl_arg(a);
+}
+
+void sme_streaming_calling_non_streaming_with_return_vl(void) __arm_streaming {
+ // expected-warning@+2 {{non-streaming callee returns a VL-dependent value to streaming caller, the streaming and non-streaming vector lengths may be different}}
+ // expected-cpp-warning@+1 {{non-streaming callee returns a VL-dependent value to streaming caller, the streaming and non-streaming vector lengths may be different}}
+ svint32x4_t r = sme_streaming_returns_vl();
+}
+
+void sme_streaming_calling_locally_streaming_with_vl_args(void) __arm_streaming {
+ svint32x4_t a;
+ // expected-1warning@+2 {{non-streaming callee receives a VL-dependent argument and the callee has an arm_locally_streaming attribute, the streaming and non-streaming vector lengths may be different}}
+ // expected-1cpp-warning@+1 {{non-streaming callee receives a VL-dependent argument and the callee has an arm_locally_streaming attribute, the streaming and non-streaming vector lengths may be different}}
+ sme_locally_streaming_with_vl_arg(a);
+}
+
+void sme_streaming_calling_locally_streaming_with_return_vl(void) __arm_streaming {
+ // expected-1warning@+2 {{non-streaming callee returns a VL-dependent value and the callee has an arm_locally_streaming attribute, the streaming and non-streaming vector lengths may be different}}
+ // expected-1cpp-warning@+1 {{non-streaming callee returns a VL-dependent value and the callee has an arm_locally_streaming attribute, the streaming and non-streaming vector lengths may be different}}
+ svint32x4_t r = sme_locally_streaming_returns_vl();
+}
+
+void sme_none_streaming_calling_locally_streaming_with_vl_args(void) __arm_streaming {
+ svint32x4_t a;
+ sme_locally_streaming_with_vl_arg(a);
+}
+
+void sme_none_streaming_calling_locally_streaming_with_return_vl(void) __arm_streaming {
+ svint32x4_t r = sme_locally_streaming_returns_vl();
+}
|
clang/lib/Sema/SemaChecking.cpp
Outdated
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); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
__arm_locally_streaming
is not a property of a function interface and therefore unrelated to a function call. That's why this code should live somewhere else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
clang/lib/Sema/SemaChecking.cpp
Outdated
if (FD->getReturnType()->isSizelessVectorType()) | ||
Diag(Loc, diag::warn_sme_non_streaming_caller_returns_to_streaming); | ||
} | ||
} else if (!FD->hasAttr<ArmLocallyStreamingAttr>()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not correct. I get a diagnostic for this case:
svint8_t bar1(void) __arm_streaming;
svint8_t foo1() __arm_streaming {
return bar1(); // incorrectly gives a diagnostic
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
// 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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you write this test without including arm_sme.h
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, but then I have to define __clang_svint32x4_t
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
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>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think 'IgnoredAttributes' is correct.
These diagnostics probably deserve to be in their own group.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But why not, There is warn_riscv_repeated_interrupt_attribute
also uses IgnoredAttributes
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the attribute is not ignored.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add new warning group AArch64SMEAttributes.
clang/lib/Sema/SemaChecking.cpp
Outdated
@@ -7513,6 +7516,38 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, | |||
} | |||
} | |||
|
|||
auto *CallerFD = dyn_cast<FunctionDecl>(CurContext); | |||
if (FD && CallerFD && Context.getTargetInfo().hasFeature("sme") && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code requires that the function definition is available (if (FD && ...)
), but the streaming mode is exposed through the interface, meaning that we shouldn't need FD
in order to emit a diagnostic.
For example:
// I would expect a warning here.
void test_n_to_s(
__SVInt32_t arg, void (*sc)(__SVInt32_t arg) __arm_streaming) {
sc(arg);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
clang/lib/Sema/SemaChecking.cpp
Outdated
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 (CalleeFnType != ArmStreaming) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic is not correct, because the following example should not result in a warning.
void sc_f(sv_ty arg) __arm_streaming_compatible;
void test_s_to_sc2(sv_ty arg) __arm_streaming {
sc_f(arg);
}```
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
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<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>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I think we can use a single message for this, e.g. "passing a VL-dependent argument to/from a function that has a different streaming-mode, is undefined behaviour"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
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">, | ||
InGroup<AArch64SMEAttributes>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These two can become a single message as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
clang/lib/Sema/SemaChecking.cpp
Outdated
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think this could be simplified further?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
clang/lib/Sema/SemaDecl.cpp
Outdated
@@ -12239,7 +12239,8 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, | |||
|
|||
if (UsesSM) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment on line 12232-12233 needs an update.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
clang/lib/Sema/SemaDecl.cpp
Outdated
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) | ||
Diag(NewFD->getLocation(), | ||
diag::warn_sme_locally_streaming_has_vl_args_returns); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be written like something along the lines of:
if (NewFD->getReturnType()->isSizelessVectorType() ||
llvm::any_of(FPT->param_types(), [](QualType T) { return T->isSizelessVectorType(); }))
Diag(....);
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
clang/lib/Sema/SemaDecl.cpp
Outdated
if (NewFD->getReturnType()->isSizelessVectorType()) | ||
Diag(NewFD->getLocation(), | ||
diag::warn_sme_locally_streaming_has_vl_args_returns); | ||
auto *FPT = NewFD->getType()->castAs<FunctionProtoType>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is FunctionPrototype
correct here? That means the check does not happen on unprototyped functions, such as __arm_locally_streaming void foo() { ... }
in C (not C++).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
clang/lib/Sema/SemaChecking.cpp
Outdated
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); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this code support the following case:
void test_sc_to_n(sv_ty arg) __arm_streaming_compatible { n(arg); } // expect a diagnostic
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
clang/lib/Sema/SemaChecking.cpp
Outdated
(ExtInfo.AArch64SMEAttributes & | ||
FunctionType::SME_PStateSMCompatibleMask)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Streaming-compatible and streaming are not the same thing. i.e. if the callee is 'streaming-compatible', IsCalleeStreaming
should be false
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -3717,6 +3717,14 @@ 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_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">, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is only undefined behaviour if the streaming VL != non-streaming VL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
clang/lib/Sema/SemaChecking.cpp
Outdated
// 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) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (CallerFD && Context.getTargetInfo().hasFeature("sme") && !IsBuiltin) { | |
if (CallerFD && !IsBuiltin) { |
It is valid to compile the following function without +sme
:
void streaming_compatible_fn(svint32_t v, void (*foo)(svint32_t)) __arm_streaming_compatible {
foo(v);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
It is not.
@@ -3717,6 +3717,16 @@ 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_pass_return_vl_to_non_streaming : Warning< | |||
"passing a VL-dependent argument to/from a function that has a different" | |||
" streaming-mode, the streaming and non-streaming vector lengths may be" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
" streaming-mode, the streaming and non-streaming vector lengths may be" | |
" streaming-mode. The streaming and non-streaming vector lengths may be" |
clang/lib/Sema/SemaChecking.cpp
Outdated
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); | ||
} else if (CallerFnType == ArmStreamingCompatible) { | ||
if ((IsCalleeStreaming || !IsCalleeStreamingCompatible) && | ||
AnyScalableArgsOrRet) | ||
Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think you can simplify this code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
"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">, | ||
InGroup<AArch64SMEAttributes>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These warnings should be disabled by default, as the user may intentionally pass/return scalable vectors, knowing something about the target they're compiling for.
clang/lib/Sema/SemaDecl.cpp
Outdated
if (DeclIsDefn) { | ||
const auto *Attr = NewFD->getAttr<ArmNewAttr>(); | ||
bool UsesSM = NewFD->hasAttr<ArmLocallyStreamingAttr>(); | ||
bool UsesZA = Attr && Attr->isNewZA(); | ||
bool UsesZT0 = Attr && Attr->isNewZT0(); | ||
|
||
if (UsesSM) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please write this without using UsesSM
, since that variable is updated further down the line. It seems better to explicitly for NewFD->hasAttr<ArmLocallyStreamingAttr>()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
clang/lib/Sema/SemaChecking.cpp
Outdated
// 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) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
It is not.
clang/lib/Sema/SemaChecking.cpp
Outdated
} | ||
if ((CallerFnType != ArmStreaming && | ||
CallerFnType != ArmStreamingCompatible && IsCalleeStreaming && | ||
AnyScalableArgsOrRet) || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you factor out AnyScalableArgsOrRet
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the update. I just left a few more suggestions to clean up the code a bit.
"passing/returning a VL-dependent argument from a function" | ||
" arm_locally_streaming attribute. The streaming and non-streaming vector" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"passing/returning a VL-dependent argument from a function" | |
" arm_locally_streaming attribute. The streaming and non-streaming vector" | |
"passing/returning a VL-dependent argument from a __arm_locally_streaming" | |
" function. The streaming and non-streaming vector" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
clang/lib/Sema/SemaChecking.cpp
Outdated
@@ -7513,6 +7516,30 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, | |||
} | |||
} | |||
|
|||
auto *CallerFD = dyn_cast<FunctionDecl>(CurContext); | |||
bool IsCalleeStreaming = | |||
(ExtInfo.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: parentheses are unnecessary.
(ExtInfo.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask); | |
ExtInfo.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask; |
Also, please move these closer to their use (inside the if blocks)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
clang/lib/Sema/SemaChecking.cpp
Outdated
bool IsCalleeStreamingCompatible = | ||
(ExtInfo.AArch64SMEAttributes & | ||
FunctionType::SME_PStateSMCompatibleMask); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: parentheses are unnecessary.
bool IsCalleeStreamingCompatible = | |
(ExtInfo.AArch64SMEAttributes & | |
FunctionType::SME_PStateSMCompatibleMask); | |
bool IsCalleeStreamingCompatible = | |
ExtInfo.AArch64SMEAttributes & | |
FunctionType::SME_PStateSMCompatibleMask; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
clang/lib/Sema/SemaChecking.cpp
Outdated
bool IsCalleeStreamingCompatible = | ||
(ExtInfo.AArch64SMEAttributes & | ||
FunctionType::SME_PStateSMCompatibleMask); | ||
bool IsBuiltin = (FD && FD->getBuiltinID()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: parentheses are unnecessary.
bool IsBuiltin = (FD && FD->getBuiltinID()); | |
bool IsBuiltin = FD && FD->getBuiltinID(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
clang/lib/Sema/SemaChecking.cpp
Outdated
(ExtInfo.AArch64SMEAttributes & | ||
FunctionType::SME_PStateSMCompatibleMask); | ||
bool IsBuiltin = (FD && FD->getBuiltinID()); | ||
AnyScalableArgsOrRet |= Proto->getReturnType()->isSizelessVectorType(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not initialise the variable with Proto->getReturnType()->isSizelessVectorType()
and then remove this separate |=
statement?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
clang/lib/Sema/SemaChecking.cpp
Outdated
@@ -7513,6 +7516,30 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, | |||
} | |||
} | |||
|
|||
auto *CallerFD = dyn_cast<FunctionDecl>(CurContext); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: move this closer to its use, preferably wrap the condition, e.g.
if (auto *CallerFD = dyn_cast<..>(..)) {
...
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
clang/lib/Sema/SemaChecking.cpp
Outdated
if ((CallerFnType != ArmStreaming && | ||
CallerFnType != ArmStreamingCompatible && IsCalleeStreaming) || | ||
(CallerFnType == ArmStreaming && !IsCalleeStreaming && | ||
!IsCalleeStreamingCompatible) || | ||
(CallerFnType == ArmStreamingCompatible && | ||
(IsCalleeStreaming || !IsCalleeStreamingCompatible))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be simplified to:
if (!IsCalleeStreamingCompatible &&
(CallerFnType == ArmStreamingCompatible ||
((CallerFnType == ArmStreaming) ^ IsCalleeStreaming)))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
clang/lib/Sema/SemaChecking.cpp
Outdated
// 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment reads a bit strange. What about:
// 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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
clang/lib/Sema/SemaChecking.cpp
Outdated
// 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. | ||
bool IsBuiltin = FD && FD->getBuiltinID(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor nit: this definition can be moved to inside the if (auto *CallerFD = ..)
block.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
It's not though.
@@ -3723,8 +3723,8 @@ def warn_sme_streaming_pass_return_vl_to_non_streaming : Warning< | |||
" different">, | |||
InGroup<AArch64SMEAttributes>, DefaultIgnore; | |||
def warn_sme_locally_streaming_has_vl_args_returns : Warning< | |||
"passing/returning a VL-dependent argument from a function" | |||
" arm_locally_streaming attribute. The streaming and non-streaming vector" | |||
"passing/returning a VL-dependent argument from a arm_locally_streaming" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"passing/returning a VL-dependent argument from a arm_locally_streaming" | |
"passing/returning a VL-dependent argument from a __arm_locally_streaming" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Sorry, just spotted this.
// A warning group AArch64 related to SME function attribues. | |
// A warning group related to AArch64 SME function attribues. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
" different">, | ||
InGroup<AArch64SMEAttributes>, DefaultIgnore; | ||
def warn_sme_locally_streaming_has_vl_args_returns : Warning< | ||
"passing/returning a VL-dependent argument from a __arm_locally_streaming" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"passing/returning a VL-dependent argument from a __arm_locally_streaming" | |
"passing/returning a VL-dependent argument to/from a __arm_locally_streaming" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
clang/lib/Sema/SemaChecking.cpp
Outdated
// 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. | ||
bool IsBuiltin = FD && FD->getBuiltinID(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
It's not though.
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. The streaming and non-streaming vector lengths may be" | ||
" different">, | ||
InGroup<AArch64SMEAttributes>, DefaultIgnore; | ||
def warn_sme_locally_streaming_has_vl_args_returns : Warning< | ||
"passing/returning a VL-dependent argument to/from a __arm_locally_streaming" | ||
" function. The streaming and non-streaming vector" | ||
" lengths may be different">, | ||
InGroup<AArch64SMEAttributes>, DefaultIgnore; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I would prefer it if you could give these warnings a 'bool' operand, such that it would give a message about either the return value or the operand, for example:
def warn_sme_streaming_pass_return_vl_to_non_streaming : Warning<
"%select{passing|returning}0 a VL-dependent argument %select{to|from}0 a function with a different"
" streaming-mode is undefined behaviour if the streaming and non-streaming vector lengths are different at runtime">,
InGroup<AArch64SMEAttributes>, DefaultIgnore;
And then emit the diagnostic like this:
if (ScalableArgs)
Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming) << /*IsArg=*/true;
if (ScalableRet)
Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming) << /*IsArg=*/false;
This results in:
warning: returning a VL-dependent argument from a function with a different streaming-mode is undefined behaviour if the streaming and non-streaming vector lengths are different at runtime
and
warning: passing a VL-dependent argument to a function with a different streaming-mode is undefined behaviour if the streaming and non-streaming vector lengths are different at runtime
I won't hold up the patch for it, but I would appreciate it if you could do this either as part of this PR or as a follow-up patch.
…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.
streaming local function from streaming function.
b255c62
to
e3c81c9
Compare
@dtemirbulatov this patch causes repro.cc:
Compilation command:
|
Reproduced the issue. |
@dtemirbulatov could you please revert to green to unblock us and continue the investigation asynchronously? |
ok, Reverting now. |
Reverted with 950bb09 |
…r size difference (llvm#79842)" This reverts commit 950bb09
…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.