Skip to content

Commit b47f63d

Browse files
authored
[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.
1 parent 18f1166 commit b47f63d

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
@@ -279,6 +279,10 @@ def err_builtin_needs_feature : Error<"%0 needs target feature %1">;
279279
def err_function_needs_feature : Error<
280280
"always_inline function %1 requires target feature '%2', but would "
281281
"be inlined into function %0 that is compiled without support for '%2'">;
282+
def err_function_always_inline_attribute_mismatch : Error<
283+
"always_inline function %1 and its caller %0 have mismatching %2 attributes">;
284+
def err_function_always_inline_new_za : Error<
285+
"always_inline function %0 has new za state">;
282286

283287
def warn_avx_calling_convention
284288
: 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;
@@ -155,6 +156,11 @@ class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
155156
}
156157
return TargetCodeGenInfo::isScalarizableAsmOperand(CGF, Ty);
157158
}
159+
160+
void checkFunctionCallABI(CodeGenModule &CGM, SourceLocation CallLoc,
161+
const FunctionDecl *Caller,
162+
const FunctionDecl *Callee,
163+
const CallArgList &Args) const override;
158164
};
159165

160166
class WindowsAArch64TargetCodeGenInfo : public AArch64TargetCodeGenInfo {
@@ -814,6 +820,43 @@ Address AArch64ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
814820
/*allowHigherAlign*/ false);
815821
}
816822

823+
static bool isStreaming(const FunctionDecl *F) {
824+
if (F->hasAttr<ArmLocallyStreamingAttr>())
825+
return true;
826+
if (const auto *T = F->getType()->getAs<FunctionProtoType>())
827+
return T->getAArch64SMEAttributes() & FunctionType::SME_PStateSMEnabledMask;
828+
return false;
829+
}
830+
831+
static bool isStreamingCompatible(const FunctionDecl *F) {
832+
if (const auto *T = F->getType()->getAs<FunctionProtoType>())
833+
return T->getAArch64SMEAttributes() &
834+
FunctionType::SME_PStateSMCompatibleMask;
835+
return false;
836+
}
837+
838+
void AArch64TargetCodeGenInfo::checkFunctionCallABI(
839+
CodeGenModule &CGM, SourceLocation CallLoc, const FunctionDecl *Caller,
840+
const FunctionDecl *Callee, const CallArgList &Args) const {
841+
if (!Caller || !Callee || !Callee->hasAttr<AlwaysInlineAttr>())
842+
return;
843+
844+
bool CallerIsStreaming = isStreaming(Caller);
845+
bool CalleeIsStreaming = isStreaming(Callee);
846+
bool CallerIsStreamingCompatible = isStreamingCompatible(Caller);
847+
bool CalleeIsStreamingCompatible = isStreamingCompatible(Callee);
848+
849+
if (!CalleeIsStreamingCompatible &&
850+
(CallerIsStreaming != CalleeIsStreaming || CallerIsStreamingCompatible))
851+
CGM.getDiags().Report(CallLoc,
852+
diag::err_function_always_inline_attribute_mismatch)
853+
<< Caller->getDeclName() << Callee->getDeclName() << "streaming";
854+
if (auto *NewAttr = Callee->getAttr<ArmNewAttr>())
855+
if (NewAttr->isNewZA())
856+
CGM.getDiags().Report(CallLoc, diag::err_function_always_inline_new_za)
857+
<< Callee->getDeclName();
858+
}
859+
817860
std::unique_ptr<TargetCodeGenInfo>
818861
CodeGen::createAArch64TargetCodeGenInfo(CodeGenModule &CGM,
819862
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)