Skip to content

Commit 7314429

Browse files
committed
[Clang][SME] Detect always_inline used with mismatched streaming attributes
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 f1fdfe6 commit 7314429

File tree

7 files changed

+66
-17
lines changed

7 files changed

+66
-17
lines changed

clang/include/clang/Basic/DiagnosticFrontendKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,8 @@ 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_alwaysinline_attribute_mismatch : Error<
283+
"always_inline function %1 and its caller %0 have mismatched %2 attributes">;
282284

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

clang/include/clang/Sema/Sema.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13832,8 +13832,17 @@ class Sema final {
1383213832
FormatArgumentPassingKind ArgPassingKind;
1383313833
};
1383413834

13835+
enum ArmStreamingType {
13836+
ArmNonStreaming,
13837+
ArmStreaming,
13838+
ArmStreamingCompatible,
13839+
ArmStreamingOrSVE2p1
13840+
};
13841+
13842+
1383513843
static bool getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember,
1383613844
bool IsVariadic, FormatStringInfo *FSI);
13845+
static ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD);
1383713846

1383813847
private:
1383913848
void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,

clang/lib/CodeGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,4 +151,5 @@ add_clang_library(clangCodeGen
151151
clangFrontend
152152
clangLex
153153
clangSerialization
154+
clangSema
154155
)

clang/lib/CodeGen/Targets/AArch64.cpp

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

99
#include "ABIInfoImpl.h"
1010
#include "TargetInfo.h"
11+
#include "clang/Basic/DiagnosticFrontend.h"
12+
#include "clang/Sema/Sema.h"
1113

1214
using namespace clang;
1315
using namespace clang::CodeGen;
@@ -155,6 +157,11 @@ class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
155157
}
156158
return TargetCodeGenInfo::isScalarizableAsmOperand(CGF, Ty);
157159
}
160+
161+
void checkFunctionCallABI(CodeGenModule &CGM, SourceLocation CallLoc,
162+
const FunctionDecl *Caller,
163+
const FunctionDecl *Callee,
164+
const CallArgList &Args) const override;
158165
};
159166

160167
class WindowsAArch64TargetCodeGenInfo : public AArch64TargetCodeGenInfo {
@@ -814,6 +821,19 @@ Address AArch64ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
814821
/*allowHigherAlign*/ false);
815822
}
816823

824+
void AArch64TargetCodeGenInfo::checkFunctionCallABI(
825+
CodeGenModule &CGM, SourceLocation CallLoc, const FunctionDecl *Caller,
826+
const FunctionDecl *Callee, const CallArgList &Args) const {
827+
if (!Callee->hasAttr<AlwaysInlineAttr>())
828+
return;
829+
830+
auto CalleeIsStreaming = Sema::getArmStreamingFnType(Callee) == Sema::ArmStreaming;
831+
auto CallerIsStreaming = Sema::getArmStreamingFnType(Caller) == Sema::ArmStreaming;
832+
833+
if (CalleeIsStreaming && !CallerIsStreaming)
834+
CGM.getDiags().Report(CallLoc, diag::err_function_alwaysinline_attribute_mismatch) << Caller->getDeclName() << Callee->getDeclName() << "streaming";
835+
}
836+
817837
std::unique_ptr<TargetCodeGenInfo>
818838
CodeGen::createAArch64TargetCodeGenInfo(CodeGenModule &CGM,
819839
AArch64ABIKind Kind) {

clang/lib/Sema/SemaChecking.cpp

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2998,13 +2998,6 @@ static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context,
29982998
llvm_unreachable("Invalid NeonTypeFlag!");
29992999
}
30003000

3001-
enum ArmStreamingType {
3002-
ArmNonStreaming,
3003-
ArmStreaming,
3004-
ArmStreamingCompatible,
3005-
ArmStreamingOrSVE2p1
3006-
};
3007-
30083001
bool Sema::ParseSVEImmChecks(
30093002
CallExpr *TheCall, SmallVector<std::tuple<int, int, int>, 3> &ImmChecks) {
30103003
// Perform all the immediate checks for this builtin call.
@@ -3145,7 +3138,7 @@ bool Sema::ParseSVEImmChecks(
31453138
return HasError;
31463139
}
31473140

3148-
static ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD) {
3141+
Sema::ArmStreamingType Sema::getArmStreamingFnType(const FunctionDecl *FD) {
31493142
if (FD->hasAttr<ArmLocallyStreamingAttr>())
31503143
return ArmStreaming;
31513144
if (const auto *T = FD->getType()->getAs<FunctionProtoType>()) {
@@ -3159,31 +3152,31 @@ static ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD) {
31593152

31603153
static void checkArmStreamingBuiltin(Sema &S, CallExpr *TheCall,
31613154
const FunctionDecl *FD,
3162-
ArmStreamingType BuiltinType) {
3163-
ArmStreamingType FnType = getArmStreamingFnType(FD);
3164-
if (BuiltinType == ArmStreamingOrSVE2p1) {
3155+
Sema::ArmStreamingType BuiltinType) {
3156+
Sema::ArmStreamingType FnType = Sema::getArmStreamingFnType(FD);
3157+
if (BuiltinType == Sema::ArmStreamingOrSVE2p1) {
31653158
// Check intrinsics that are available in [sve2p1 or sme/sme2].
31663159
llvm::StringMap<bool> CallerFeatureMap;
31673160
S.Context.getFunctionFeatureMap(CallerFeatureMap, FD);
31683161
if (Builtin::evaluateRequiredTargetFeatures("sve2p1", CallerFeatureMap))
3169-
BuiltinType = ArmStreamingCompatible;
3162+
BuiltinType = Sema::ArmStreamingCompatible;
31703163
else
3171-
BuiltinType = ArmStreaming;
3164+
BuiltinType = Sema::ArmStreaming;
31723165
}
31733166

3174-
if (FnType == ArmStreaming && BuiltinType == ArmNonStreaming) {
3167+
if (FnType == Sema::ArmStreaming && BuiltinType == Sema::ArmNonStreaming) {
31753168
S.Diag(TheCall->getBeginLoc(), diag::warn_attribute_arm_sm_incompat_builtin)
31763169
<< TheCall->getSourceRange() << "streaming";
31773170
}
31783171

3179-
if (FnType == ArmStreamingCompatible &&
3180-
BuiltinType != ArmStreamingCompatible) {
3172+
if (FnType == Sema::ArmStreamingCompatible &&
3173+
BuiltinType != Sema::ArmStreamingCompatible) {
31813174
S.Diag(TheCall->getBeginLoc(), diag::warn_attribute_arm_sm_incompat_builtin)
31823175
<< TheCall->getSourceRange() << "streaming compatible";
31833176
return;
31843177
}
31853178

3186-
if (FnType == ArmNonStreaming && BuiltinType == ArmStreaming) {
3179+
if (FnType == Sema::ArmNonStreaming && BuiltinType == Sema::ArmStreaming) {
31873180
S.Diag(TheCall->getBeginLoc(), diag::warn_attribute_arm_sm_incompat_builtin)
31883181
<< TheCall->getSourceRange() << "non-streaming";
31893182
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %clang --target=aarch64-none-linux-gnu -march=armv9-a+sme -O3 -S -Xclang -verify %s
2+
3+
// Conflicting attributes when using always_inline
4+
__attribute__((always_inline)) __arm_locally_streaming
5+
int inlined_fn_local(void) {
6+
return 42;
7+
}
8+
// expected-error@+1 {{always_inline function 'inlined_fn_local' and its caller 'inlined_fn_caller' have mismatched streaming attributes}}
9+
int inlined_fn_caller(void) { return inlined_fn_local(); }
10+
__arm_locally_streaming
11+
int inlined_fn_caller_local(void) { return inlined_fn_local(); }
12+
int inlined_fn_caller_streaming(void) __arm_streaming { return inlined_fn_local(); }
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %clang --target=aarch64-none-linux-gnu -march=armv9-a+sme -O3 -S -Xclang -verify %s
2+
3+
// Conflicting attributes when using always_inline
4+
__attribute__((always_inline))
5+
int inlined_fn_streaming(void) __arm_streaming {
6+
return 42;
7+
}
8+
// expected-error@+1 {{always_inline function 'inlined_fn_streaming' and its caller 'inlined_fn_caller' have mismatched streaming attributes}}
9+
int inlined_fn_caller(void) { return inlined_fn_streaming(); }
10+
__arm_locally_streaming
11+
int inlined_fn_caller_local(void) { return inlined_fn_streaming(); }
12+
int inlined_fn_caller_streaming(void) __arm_streaming { return inlined_fn_streaming(); }

0 commit comments

Comments
 (0)