Skip to content

Commit 079b5b6

Browse files
SamTebbs33wwwatermiao
authored andcommitted
[Clang][SME] Detect always_inline used with mismatched streaming attributes (#77936)
This patch adds an error that is emitted when a streaming function is marked as always_inline and is called from a non-streaming function. Signed-off-by: chenmiao <[email protected]> Signed-off-by: chenmiao <[email protected]>
1 parent 6a0305e commit 079b5b6

File tree

3 files changed

+94
-0
lines changed

3 files changed

+94
-0
lines changed

clang/include/clang/Basic/DiagnosticFrontendKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,10 @@ def err_builtin_needs_feature : Error<"%0 needs target feature %1">;
273273
def err_function_needs_feature : Error<
274274
"always_inline function %1 requires target feature '%2', but would "
275275
"be inlined into function %0 that is compiled without support for '%2'">;
276+
def err_function_always_inline_attribute_mismatch : Error<
277+
"always_inline function %1 and its caller %0 have mismatching %2 attributes">;
278+
def err_function_always_inline_new_za : Error<
279+
"always_inline function %0 has new za state">;
276280

277281
def warn_avx_calling_convention
278282
: Warning<"AVX vector %select{return|argument}0 of type %1 without '%2' "

clang/lib/CodeGen/Targets/AArch64.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "ABIInfoImpl.h"
1010
#include "TargetInfo.h"
11+
#include "clang/Basic/DiagnosticFrontend.h"
1112

1213
using namespace clang;
1314
using namespace clang::CodeGen;
@@ -151,6 +152,11 @@ class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
151152
}
152153
return TargetCodeGenInfo::isScalarizableAsmOperand(CGF, Ty);
153154
}
155+
156+
void checkFunctionCallABI(CodeGenModule &CGM, SourceLocation CallLoc,
157+
const FunctionDecl *Caller,
158+
const FunctionDecl *Callee,
159+
const CallArgList &Args) const override;
154160
};
155161

156162
class WindowsAArch64TargetCodeGenInfo : public AArch64TargetCodeGenInfo {
@@ -811,6 +817,43 @@ Address AArch64ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
811817
/*allowHigherAlign*/ false);
812818
}
813819

820+
static bool isStreaming(const FunctionDecl *F) {
821+
if (F->hasAttr<ArmLocallyStreamingAttr>())
822+
return true;
823+
if (const auto *T = F->getType()->getAs<FunctionProtoType>())
824+
return T->getAArch64SMEAttributes() & FunctionType::SME_PStateSMEnabledMask;
825+
return false;
826+
}
827+
828+
static bool isStreamingCompatible(const FunctionDecl *F) {
829+
if (const auto *T = F->getType()->getAs<FunctionProtoType>())
830+
return T->getAArch64SMEAttributes() &
831+
FunctionType::SME_PStateSMCompatibleMask;
832+
return false;
833+
}
834+
835+
void AArch64TargetCodeGenInfo::checkFunctionCallABI(
836+
CodeGenModule &CGM, SourceLocation CallLoc, const FunctionDecl *Caller,
837+
const FunctionDecl *Callee, const CallArgList &Args) const {
838+
if (!Caller || !Callee || !Callee->hasAttr<AlwaysInlineAttr>())
839+
return;
840+
841+
bool CallerIsStreaming = isStreaming(Caller);
842+
bool CalleeIsStreaming = isStreaming(Callee);
843+
bool CallerIsStreamingCompatible = isStreamingCompatible(Caller);
844+
bool CalleeIsStreamingCompatible = isStreamingCompatible(Callee);
845+
846+
if (!CalleeIsStreamingCompatible &&
847+
(CallerIsStreaming != CalleeIsStreaming || CallerIsStreamingCompatible))
848+
CGM.getDiags().Report(CallLoc,
849+
diag::err_function_always_inline_attribute_mismatch)
850+
<< Caller->getDeclName() << Callee->getDeclName() << "streaming";
851+
if (auto *NewAttr = Callee->getAttr<ArmNewAttr>())
852+
if (NewAttr->isNewZA())
853+
CGM.getDiags().Report(CallLoc, diag::err_function_always_inline_new_za)
854+
<< Callee->getDeclName();
855+
}
856+
814857
std::unique_ptr<TargetCodeGenInfo>
815858
CodeGen::createAArch64TargetCodeGenInfo(CodeGenModule &CGM,
816859
AArch64ABIKind Kind) {
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -S -target-feature +sme -verify -DTEST_NONE %s
2+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -S -target-feature +sme -verify -DTEST_COMPATIBLE %s
3+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -S -target-feature +sme -verify -DTEST_STREAMING %s
4+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -S -target-feature +sme -verify -DTEST_LOCALLY %s
5+
6+
#define __ai __attribute__((always_inline))
7+
__ai void inlined_fn(void) {}
8+
__ai void inlined_fn_streaming_compatible(void) __arm_streaming_compatible {}
9+
__ai void inlined_fn_streaming(void) __arm_streaming {}
10+
__ai __arm_locally_streaming void inlined_fn_local(void) {}
11+
12+
#ifdef TEST_NONE
13+
void caller(void) {
14+
inlined_fn();
15+
inlined_fn_streaming_compatible();
16+
inlined_fn_streaming(); // expected-error {{always_inline function 'inlined_fn_streaming' and its caller 'caller' have mismatching streaming attributes}}
17+
inlined_fn_local(); // expected-error {{always_inline function 'inlined_fn_local' and its caller 'caller' have mismatching streaming attributes}}
18+
}
19+
#endif
20+
21+
#ifdef TEST_COMPATIBLE
22+
void caller_compatible(void) __arm_streaming_compatible {
23+
inlined_fn(); // expected-error {{always_inline function 'inlined_fn' and its caller 'caller_compatible' have mismatching streaming attributes}}
24+
inlined_fn_streaming_compatible();
25+
inlined_fn_streaming(); // expected-error {{always_inline function 'inlined_fn_streaming' and its caller 'caller_compatible' have mismatching streaming attributes}}
26+
inlined_fn_local(); // expected-error {{always_inline function 'inlined_fn_local' and its caller 'caller_compatible' have mismatching streaming attributes}}
27+
}
28+
#endif
29+
30+
#ifdef TEST_STREAMING
31+
void caller_streaming(void) __arm_streaming {
32+
inlined_fn(); // expected-error {{always_inline function 'inlined_fn' and its caller 'caller_streaming' have mismatching streaming attributes}}
33+
inlined_fn_streaming_compatible();
34+
inlined_fn_streaming();
35+
inlined_fn_local();
36+
}
37+
#endif
38+
39+
#ifdef TEST_LOCALLY
40+
__arm_locally_streaming
41+
void caller_local(void) {
42+
inlined_fn(); // expected-error {{always_inline function 'inlined_fn' and its caller 'caller_local' have mismatching streaming attributes}}
43+
inlined_fn_streaming_compatible();
44+
inlined_fn_streaming();
45+
inlined_fn_local();
46+
}
47+
#endif

0 commit comments

Comments
 (0)