Skip to content

Commit 2c12a3d

Browse files
authored
[Sema][AArch64] Emit error for mismatched VLs on streaming mode transitions (llvm#159131)
Update Sema::checkCall to handle the case where a call involves a streaming mode transition and passes or returns scalable vector types. Previously, Clang always issued a warning in this case, noting that the streaming and non-streaming vector lengths may differ at runtime. With this change: - if both `-msve-vector-bits` and `-msve-streaming-vector-bits` are specified and produce different fixed VL values, Clang now emits an error rather than a warning - If either flag is missing or vector lengths are equal, the diagnostic remains a warning
1 parent 2c754ec commit 2c12a3d

File tree

3 files changed

+143
-4
lines changed

3 files changed

+143
-4
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3983,6 +3983,14 @@ def warn_sme_locally_streaming_has_vl_args_returns : Warning<
39833983
"%select{returning|passing}0 a VL-dependent argument %select{from|to}0 a locally streaming function is undefined"
39843984
" behaviour when the streaming and non-streaming vector lengths are different at runtime">,
39853985
InGroup<AArch64SMEAttributes>, DefaultIgnore;
3986+
def warn_sme_streaming_compatible_vl_mismatch : Warning<
3987+
"%select{returning|passing}0 a VL-dependent argument %select{from|to}0 a %select{non-streaming|streaming}1"
3988+
" function is undefined behaviour when the streaming-compatible caller is%select{| not}1 in streaming"
3989+
" mode, because the streaming vector length (%2 bit) and non-streaming vector length (%3 bit) differ">,
3990+
InGroup<AArch64SMEAttributes>, DefaultIgnore;
3991+
def err_sme_streaming_transition_vl_mismatch : Error<
3992+
"%select{returning|passing}0 a VL-dependent argument %select{from|to}0 a function with a different"
3993+
" streaming-mode is undefined behaviour because the streaming vector length (%1 bit) and non-streaming vector length (%2 bit) differ">;
39863994
def err_conflicting_attributes_arm_agnostic : Error<
39873995
"__arm_agnostic(\"sme_za_state\") cannot share ZA state with its caller">;
39883996
def err_conflicting_attributes_arm_state : Error<

clang/lib/Sema/SemaChecking.cpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3855,6 +3855,8 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
38553855
// If the call requires a streaming-mode change and has scalable vector
38563856
// arguments or return values, then warn the user that the streaming and
38573857
// non-streaming vector lengths may be different.
3858+
// When both streaming and non-streaming vector lengths are defined and
3859+
// mismatched, produce an error.
38583860
const auto *CallerFD = dyn_cast<FunctionDecl>(CurContext);
38593861
if (CallerFD && (!FD || !FD->getBuiltinID()) &&
38603862
(IsScalableArg || IsScalableRet)) {
@@ -3867,12 +3869,30 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
38673869
if (!IsCalleeStreamingCompatible &&
38683870
(CallerFnType == SemaARM::ArmStreamingCompatible ||
38693871
((CallerFnType == SemaARM::ArmStreaming) ^ IsCalleeStreaming))) {
3872+
const LangOptions &LO = getLangOpts();
3873+
unsigned VL = LO.VScaleMin * 128;
3874+
unsigned SVL = LO.VScaleStreamingMin * 128;
3875+
bool IsVLMismatch = VL && SVL && VL != SVL;
3876+
3877+
auto EmitDiag = [&](bool IsArg) {
3878+
if (IsVLMismatch) {
3879+
if (CallerFnType == SemaARM::ArmStreamingCompatible)
3880+
// Emit warning for streaming-compatible callers
3881+
Diag(Loc, diag::warn_sme_streaming_compatible_vl_mismatch)
3882+
<< IsArg << IsCalleeStreaming << SVL << VL;
3883+
else
3884+
// Emit error otherwise
3885+
Diag(Loc, diag::err_sme_streaming_transition_vl_mismatch)
3886+
<< IsArg << SVL << VL;
3887+
} else
3888+
Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming)
3889+
<< IsArg;
3890+
};
3891+
38703892
if (IsScalableArg)
3871-
Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming)
3872-
<< /*IsArg=*/true;
3893+
EmitDiag(true);
38733894
if (IsScalableRet)
3874-
Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming)
3875-
<< /*IsArg=*/false;
3895+
EmitDiag(false);
38763896
}
38773897
}
38783898

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Case 1: No vscale flags — should only produce warnings
2+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +bf16 -target-feature +sme -target-feature +sme2 -target-feature +sve -Waarch64-sme-attributes -fsyntax-only -verify=expected-noflags %s
3+
4+
// Case 2: Explicit mismatch in vscale flags — should produce errors for
5+
// streaming and non-streaming callers
6+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +bf16 -target-feature +sme -target-feature +sme2 -target-feature +sve -Waarch64-sme-attributes -fsyntax-only -mvscale-min=1 -mvscale-max=1 -mvscale-streaming-min=2 -mvscale-streaming-max=2 -verify=expected-flags %s
7+
8+
void sme_streaming_with_vl_arg(__SVInt8_t a) __arm_streaming;
9+
10+
__SVInt8_t sme_streaming_returns_vl(void) __arm_streaming;
11+
12+
void sme_streaming_compatible_with_vl_arg(__SVInt8_t a) __arm_streaming_compatible;
13+
14+
__SVInt8_t sme_streaming_compatible_returns_vl(void) __arm_streaming_compatible;
15+
16+
void sme_no_streaming_with_vl_arg(__SVInt8_t a);
17+
18+
__SVInt8_t sme_no_streaming_returns_vl(void);
19+
20+
21+
void sme_no_streaming_calling_streaming_with_vl_args() {
22+
__SVInt8_t a;
23+
// expected-noflags-warning@+2 {{passing a VL-dependent argument to a function with a different streaming-mode is undefined behaviour when the streaming and non-streaming vector lengths are different at runtime}}
24+
// expected-flags-error@+1 {{passing a VL-dependent argument to a function with a different streaming-mode is undefined behaviour because the streaming vector length (256 bit) and non-streaming vector length (128 bit) differ}}
25+
sme_streaming_with_vl_arg(a);
26+
}
27+
28+
void sme_no_streaming_calling_streaming_with_return_vl() {
29+
// expected-noflags-warning@+2 {{returning a VL-dependent argument from a function with a different streaming-mode is undefined behaviour when the streaming and non-streaming vector lengths are different at runtime}}
30+
// expected-flags-error@+1 {{returning a VL-dependent argument from a function with a different streaming-mode is undefined behaviour because the streaming vector length (256 bit) and non-streaming vector length (128 bit) differ}}
31+
__SVInt8_t r = sme_streaming_returns_vl();
32+
}
33+
34+
void sme_streaming_calling_non_streaming_with_vl_args(void) __arm_streaming {
35+
__SVInt8_t a;
36+
// expected-noflags-warning@+2 {{passing a VL-dependent argument to a function with a different streaming-mode is undefined behaviour when the streaming and non-streaming vector lengths are different at runtime}}
37+
// expected-flags-error@+1 {{passing a VL-dependent argument to a function with a different streaming-mode is undefined behaviour because the streaming vector length (256 bit) and non-streaming vector length (128 bit) differ}}
38+
sme_no_streaming_with_vl_arg(a);
39+
}
40+
41+
void sme_streaming_calling_non_streaming_with_return_vl(void) __arm_streaming {
42+
// expected-noflags-warning@+2 {{returning a VL-dependent argument from a function with a different streaming-mode is undefined behaviour when the streaming and non-streaming vector lengths are different at runtime}}
43+
// expected-flags-error@+1 {{returning a VL-dependent argument from a function with a different streaming-mode is undefined behaviour because the streaming vector length (256 bit) and non-streaming vector length (128 bit) differ}}
44+
__SVInt8_t r = sme_no_streaming_returns_vl();
45+
}
46+
47+
void sme_streaming_compatible_calling_streaming_with_vl_args(__SVInt8_t arg) __arm_streaming_compatible {
48+
// expected-noflags-warning@+2 {{passing a VL-dependent argument to a function with a different streaming-mode is undefined behaviour when the streaming and non-streaming vector lengths are different at runtime}}
49+
// expected-flags-warning@+1 {{passing a VL-dependent argument to a streaming function is undefined behaviour when the streaming-compatible caller is not in streaming mode, because the streaming vector length (256 bit) and non-streaming vector length (128 bit) differ}}
50+
sme_streaming_with_vl_arg(arg);
51+
}
52+
53+
void sme_streaming_compatible_calling_sme_streaming_return_vl(void) __arm_streaming_compatible {
54+
// expected-noflags-warning@+2 {{returning a VL-dependent argument from a function with a different streaming-mode is undefined behaviour when the streaming and non-streaming vector lengths are different at runtime}}
55+
// expected-flags-warning@+1 {{returning a VL-dependent argument from a streaming function is undefined behaviour when the streaming-compatible caller is not in streaming mode, because the streaming vector length (256 bit) and non-streaming vector length (128 bit) differ}}
56+
__SVInt8_t r = sme_streaming_returns_vl();
57+
}
58+
59+
void sme_streaming_compatible_calling_no_streaming_with_vl_args(__SVInt8_t arg) __arm_streaming_compatible {
60+
// expected-noflags-warning@+2 {{passing a VL-dependent argument to a function with a different streaming-mode is undefined behaviour when the streaming and non-streaming vector lengths are different at runtime}}
61+
// expected-flags-warning@+1 {{passing a VL-dependent argument to a non-streaming function is undefined behaviour when the streaming-compatible caller is in streaming mode, because the streaming vector length (256 bit) and non-streaming vector length (128 bit) differ}}
62+
sme_no_streaming_with_vl_arg(arg);
63+
}
64+
65+
void sme_streaming_compatible_calling_no_sme_streaming_return_vl(void) __arm_streaming_compatible {
66+
// expected-noflags-warning@+2 {{returning a VL-dependent argument from a function with a different streaming-mode is undefined behaviour when the streaming and non-streaming vector lengths are different at runtime}}
67+
// expected-flags-warning@+1 {{returning a VL-dependent argument from a non-streaming function is undefined behaviour when the streaming-compatible caller is in streaming mode, because the streaming vector length (256 bit) and non-streaming vector length (128 bit) differ}}
68+
__SVInt8_t r = sme_no_streaming_returns_vl();
69+
}
70+
71+
void sme_streaming_calling_streaming_with_vl_args(__SVInt8_t a) __arm_streaming {
72+
sme_streaming_with_vl_arg(a);
73+
}
74+
75+
void sme_streaming_calling_streaming_with_return_vl(void) __arm_streaming {
76+
__SVInt8_t r = sme_streaming_returns_vl();
77+
}
78+
79+
void sme_streaming_calling_streaming_compatible_with_vl_args(__SVInt8_t a) __arm_streaming {
80+
sme_streaming_compatible_with_vl_arg(a);
81+
}
82+
83+
void sme_streaming_calling_streaming_compatible_with_return_vl(void) __arm_streaming {
84+
__SVInt8_t r = sme_streaming_compatible_returns_vl();
85+
}
86+
87+
void sme_no_streaming_calling_streaming_compatible_with_vl_args() {
88+
__SVInt8_t a;
89+
sme_streaming_compatible_with_vl_arg(a);
90+
}
91+
92+
void sme_no_streaming_calling_streaming_compatible_with_return_vl() {
93+
__SVInt8_t r = sme_streaming_compatible_returns_vl();
94+
}
95+
96+
void sme_no_streaming_calling_non_streaming_with_vl_args() {
97+
__SVInt8_t a;
98+
sme_no_streaming_with_vl_arg(a);
99+
}
100+
101+
void sme_no_streaming_calling_non_streaming_with_return_vl() {
102+
__SVInt8_t r = sme_no_streaming_returns_vl();
103+
}
104+
105+
void sme_streaming_compatible_calling_streaming_compatible_with_vl_args(__SVInt8_t arg) __arm_streaming_compatible {
106+
sme_streaming_compatible_with_vl_arg(arg);
107+
}
108+
109+
void sme_streaming_compatible_calling_streaming_compatible_with_return_vl(void) __arm_streaming_compatible {
110+
__SVInt8_t r = sme_streaming_compatible_returns_vl();
111+
}

0 commit comments

Comments
 (0)