Skip to content

Commit 1652d44

Browse files
[Clang] Amend SME attributes with support for ZT0. (#77941)
This patch builds on top of #76971 and implements support for: * __arm_new("zt0") * __arm_in("zt0") * __arm_out("zt0") * __arm_inout("zt0") * __arm_preserves("zt0")
1 parent 5c7bbe3 commit 1652d44

13 files changed

+186
-5
lines changed

clang/include/clang/AST/Type.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4056,10 +4056,12 @@ class FunctionType : public Type {
40564056
// Describes the value of the state using ArmStateValue.
40574057
SME_ZAShift = 2,
40584058
SME_ZAMask = 0b111 << SME_ZAShift,
4059+
SME_ZT0Shift = 5,
4060+
SME_ZT0Mask = 0b111 << SME_ZT0Shift,
40594061

4060-
SME_AttributeMask = 0b111'111 // We only support maximum 6 bits because of
4061-
// the bitmask in FunctionTypeArmAttributes
4062-
// and ExtProtoInfo.
4062+
SME_AttributeMask =
4063+
0b111'111'11 // We can't support more than 8 bits because of
4064+
// the bitmask in FunctionTypeExtraBitfields.
40634065
};
40644066

40654067
enum ArmStateValue : unsigned {
@@ -4074,13 +4076,17 @@ class FunctionType : public Type {
40744076
return (ArmStateValue)((AttrBits & SME_ZAMask) >> SME_ZAShift);
40754077
}
40764078

4079+
static ArmStateValue getArmZT0State(unsigned AttrBits) {
4080+
return (ArmStateValue)((AttrBits & SME_ZT0Mask) >> SME_ZT0Shift);
4081+
}
4082+
40774083
/// A holder for Arm type attributes as described in the Arm C/C++
40784084
/// Language extensions which are not particularly common to all
40794085
/// types and therefore accounted separately from FunctionTypeBitfields.
40804086
struct alignas(void *) FunctionTypeArmAttributes {
40814087
/// Any AArch64 SME ACLE type attributes that need to be propagated
40824088
/// on declarations and function pointers.
4083-
unsigned AArch64SMEAttributes : 6;
4089+
unsigned AArch64SMEAttributes : 8;
40844090

40854091
FunctionTypeArmAttributes() : AArch64SMEAttributes(SME_NormalFunction) {}
40864092
};
@@ -4266,7 +4272,7 @@ class FunctionProtoType final
42664272
FunctionType::ExtInfo ExtInfo;
42674273
unsigned Variadic : 1;
42684274
unsigned HasTrailingReturn : 1;
4269-
unsigned AArch64SMEAttributes : 6;
4275+
unsigned AArch64SMEAttributes : 8;
42704276
Qualifiers TypeQuals;
42714277
RefQualifierKind RefQualifier = RQ_None;
42724278
ExceptionSpecInfo ExceptionSpec;

clang/include/clang/Basic/Attr.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2552,6 +2552,9 @@ def ArmNew : InheritableAttr, TargetSpecificAttr<TargetAArch64> {
25522552
bool isNewZA() const {
25532553
return llvm::is_contained(newArgs(), "za");
25542554
}
2555+
bool isNewZT0() const {
2556+
return llvm::is_contained(newArgs(), "zt0");
2557+
}
25552558
}];
25562559
}
25572560

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3706,10 +3706,14 @@ def err_sme_call_in_non_sme_target : Error<
37063706
"call to a streaming function requires 'sme'">;
37073707
def err_sme_za_call_no_za_state : Error<
37083708
"call to a shared ZA function requires the caller to have ZA state">;
3709+
def err_sme_zt0_call_no_zt0_state : Error<
3710+
"call to a shared ZT0 function requires the caller to have ZT0 state">;
37093711
def err_sme_definition_using_sm_in_non_sme_target : Error<
37103712
"function executed in streaming-SVE mode requires 'sme'">;
37113713
def err_sme_definition_using_za_in_non_sme_target : Error<
37123714
"function using ZA state requires 'sme'">;
3715+
def err_sme_definition_using_zt0_in_non_sme2_target : Error<
3716+
"function using ZT0 state requires 'sme2'">;
37133717
def err_conflicting_attributes_arm_state : Error<
37143718
"conflicting attributes for state '%0'">;
37153719
def err_unknown_arm_state : Error<

clang/lib/AST/TypePrinter.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,14 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
951951
OS << " __arm_out(\"za\")";
952952
if (FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_InOut)
953953
OS << " __arm_inout(\"za\")";
954+
if (FunctionType::getArmZT0State(SMEBits) == FunctionType::ARM_Preserves)
955+
OS << " __arm_preserves(\"zt0\")";
956+
if (FunctionType::getArmZT0State(SMEBits) == FunctionType::ARM_In)
957+
OS << " __arm_in(\"zt0\")";
958+
if (FunctionType::getArmZT0State(SMEBits) == FunctionType::ARM_Out)
959+
OS << " __arm_out(\"zt0\")";
960+
if (FunctionType::getArmZT0State(SMEBits) == FunctionType::ARM_InOut)
961+
OS << " __arm_inout(\"zt0\")";
954962

955963
printFunctionAfter(Info, OS);
956964

clang/lib/CodeGen/CGCall.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1782,6 +1782,16 @@ static void AddAttributesFromFunctionProtoType(ASTContext &Ctx,
17821782
FuncAttrs.addAttribute("aarch64_pstate_za_shared");
17831783
FuncAttrs.addAttribute("aarch64_pstate_za_preserved");
17841784
}
1785+
1786+
// ZT0
1787+
if (FunctionType::getArmZT0State(SMEBits) == FunctionType::ARM_Preserves)
1788+
FuncAttrs.addAttribute("aarch64_preserves_zt0");
1789+
if (FunctionType::getArmZT0State(SMEBits) == FunctionType::ARM_In)
1790+
FuncAttrs.addAttribute("aarch64_in_zt0");
1791+
if (FunctionType::getArmZT0State(SMEBits) == FunctionType::ARM_Out)
1792+
FuncAttrs.addAttribute("aarch64_out_zt0");
1793+
if (FunctionType::getArmZT0State(SMEBits) == FunctionType::ARM_InOut)
1794+
FuncAttrs.addAttribute("aarch64_inout_zt0");
17851795
}
17861796

17871797
static void AddAttributesFromAssumes(llvm::AttrBuilder &FuncAttrs,

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2415,6 +2415,8 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
24152415
if (auto *Attr = D->getAttr<ArmNewAttr>()) {
24162416
if (Attr->isNewZA())
24172417
B.addAttribute("aarch64_pstate_za_new");
2418+
if (Attr->isNewZT0())
2419+
B.addAttribute("aarch64_new_zt0");
24182420
}
24192421

24202422
// Track whether we need to add the optnone LLVM attribute,

clang/lib/Sema/SemaChecking.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7548,6 +7548,28 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
75487548
if (!CallerHasZAState)
75497549
Diag(Loc, diag::err_sme_za_call_no_za_state);
75507550
}
7551+
7552+
// If the callee uses AArch64 SME ZT0 state but the caller doesn't define
7553+
// any, then this is an error.
7554+
FunctionType::ArmStateValue ArmZT0State =
7555+
FunctionType::getArmZT0State(ExtInfo.AArch64SMEAttributes);
7556+
if (ArmZT0State != FunctionType::ARM_None) {
7557+
bool CallerHasZT0State = false;
7558+
if (const auto *CallerFD = dyn_cast<FunctionDecl>(CurContext)) {
7559+
auto *Attr = CallerFD->getAttr<ArmNewAttr>();
7560+
if (Attr && Attr->isNewZT0())
7561+
CallerHasZT0State = true;
7562+
else if (const auto *FPT =
7563+
CallerFD->getType()->getAs<FunctionProtoType>())
7564+
CallerHasZT0State =
7565+
FunctionType::getArmZT0State(
7566+
FPT->getExtProtoInfo().AArch64SMEAttributes) !=
7567+
FunctionType::ARM_None;
7568+
}
7569+
7570+
if (!CallerHasZT0State)
7571+
Diag(Loc, diag::err_sme_zt0_call_no_zt0_state);
7572+
}
75517573
}
75527574

75537575
if (FDecl && FDecl->hasAttr<AllocAlignAttr>()) {

clang/lib/Sema/SemaDecl.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12234,12 +12234,15 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
1223412234
const auto *Attr = NewFD->getAttr<ArmNewAttr>();
1223512235
bool UsesSM = NewFD->hasAttr<ArmLocallyStreamingAttr>();
1223612236
bool UsesZA = Attr && Attr->isNewZA();
12237+
bool UsesZT0 = Attr && Attr->isNewZT0();
1223712238
if (const auto *FPT = NewFD->getType()->getAs<FunctionProtoType>()) {
1223812239
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
1223912240
UsesSM |=
1224012241
EPI.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask;
1224112242
UsesZA |= FunctionType::getArmZAState(EPI.AArch64SMEAttributes) !=
1224212243
FunctionType::ARM_None;
12244+
UsesZT0 |= FunctionType::getArmZT0State(EPI.AArch64SMEAttributes) !=
12245+
FunctionType::ARM_None;
1224312246
}
1224412247

1224512248
if (UsesSM || UsesZA) {
@@ -12254,6 +12257,14 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
1225412257
diag::err_sme_definition_using_za_in_non_sme_target);
1225512258
}
1225612259
}
12260+
if (UsesZT0) {
12261+
llvm::StringMap<bool> FeatureMap;
12262+
Context.getFunctionFeatureMap(FeatureMap, NewFD);
12263+
if (!FeatureMap.contains("sme2")) {
12264+
Diag(NewFD->getLocation(),
12265+
diag::err_sme_definition_using_zt0_in_non_sme2_target);
12266+
}
12267+
}
1225712268
}
1225812269

1225912270
return Redeclaration;

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8994,6 +8994,7 @@ static void handleArmNewAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
89948994
}
89958995

89968996
bool HasZA = false;
8997+
bool HasZT0 = false;
89978998
for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
89988999
StringRef StateName;
89999000
SourceLocation LiteralLoc;
@@ -9002,6 +9003,8 @@ static void handleArmNewAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
90029003

90039004
if (StateName == "za")
90049005
HasZA = true;
9006+
else if (StateName == "zt0")
9007+
HasZT0 = true;
90059008
else {
90069009
S.Diag(LiteralLoc, diag::err_unknown_arm_state) << StateName;
90079010
AL.setInvalid();
@@ -9018,6 +9021,11 @@ static void handleArmNewAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
90189021
if (HasZA && ZAState != FunctionType::ARM_None &&
90199022
checkArmNewAttrMutualExclusion(S, AL, FPT, ZAState, "za"))
90209023
return;
9024+
FunctionType::ArmStateValue ZT0State =
9025+
FunctionType::getArmZT0State(FPT->getAArch64SMEAttributes());
9026+
if (HasZT0 && ZT0State != FunctionType::ARM_None &&
9027+
checkArmNewAttrMutualExclusion(S, AL, FPT, ZT0State, "zt0"))
9028+
return;
90219029
}
90229030

90239031
D->dropAttr<ArmNewAttr>();

clang/lib/Sema/SemaType.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7938,6 +7938,9 @@ static bool handleArmStateAttribute(Sema &S,
79387938
if (StateName == "za") {
79397939
Shift = FunctionType::SME_ZAShift;
79407940
ExistingState = FunctionType::getArmZAState(EPI.AArch64SMEAttributes);
7941+
} else if (StateName == "zt0") {
7942+
Shift = FunctionType::SME_ZT0Shift;
7943+
ExistingState = FunctionType::getArmZT0State(EPI.AArch64SMEAttributes);
79417944
} else {
79427945
S.Diag(LiteralLoc, diag::err_unknown_arm_state) << StateName;
79437946
Attr.setInvalid();
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme2 \
2+
// RUN: -S -disable-O0-optnone -Werror -emit-llvm -o - %s \
3+
// RUN: | opt -S -passes=mem2reg \
4+
// RUN: | opt -S -passes=inline \
5+
// RUN: | FileCheck %s
6+
7+
// Test the attributes for ZT0 and their mappings to LLVM IR.
8+
9+
extern "C" {
10+
11+
// CHECK-LABEL: @in_zt0()
12+
// CHECK-SAME: #[[ZT0_IN:[0-9]+]]
13+
void in_zt0() __arm_in("zt0") { }
14+
15+
// CHECK-LABEL: @out_zt0()
16+
// CHECK-SAME: #[[ZT0_OUT:[0-9]+]]
17+
void out_zt0() __arm_out("zt0") { }
18+
19+
// CHECK-LABEL: @inout_zt0()
20+
// CHECK-SAME: #[[ZT0_INOUT:[0-9]+]]
21+
void inout_zt0() __arm_inout("zt0") { }
22+
23+
// CHECK-LABEL: @preserves_zt0()
24+
// CHECK-SAME: #[[ZT0_PRESERVED:[0-9]+]]
25+
void preserves_zt0() __arm_preserves("zt0") { }
26+
27+
// CHECK-LABEL: @new_zt0()
28+
// CHECK-SAME: #[[ZT0_NEW:[0-9]+]]
29+
__arm_new("zt0") void new_zt0() { }
30+
31+
// CHECK-LABEL: @in_za_zt0()
32+
// CHECK-SAME: #[[ZA_ZT0_IN:[0-9]+]]
33+
void in_za_zt0() __arm_in("za", "zt0") { }
34+
35+
// CHECK-LABEL: @out_za_zt0()
36+
// CHECK-SAME: #[[ZA_ZT0_OUT:[0-9]+]]
37+
void out_za_zt0() __arm_out("za", "zt0") { }
38+
39+
// CHECK-LABEL: @inout_za_zt0()
40+
// CHECK-SAME: #[[ZA_ZT0_INOUT:[0-9]+]]
41+
void inout_za_zt0() __arm_inout("za", "zt0") { }
42+
43+
// CHECK-LABEL: @preserves_za_zt0()
44+
// CHECK-SAME: #[[ZA_ZT0_PRESERVED:[0-9]+]]
45+
void preserves_za_zt0() __arm_preserves("za", "zt0") { }
46+
47+
// CHECK-LABEL: @new_za_zt0()
48+
// CHECK-SAME: #[[ZA_ZT0_NEW:[0-9]+]]
49+
__arm_new("za", "zt0") void new_za_zt0() { }
50+
51+
}
52+
53+
// CHECK: attributes #[[ZT0_IN]] = {{{.*}} "aarch64_in_zt0" {{.*}}}
54+
// CHECK: attributes #[[ZT0_OUT]] = {{{.*}} "aarch64_out_zt0" {{.*}}}
55+
// CHECK: attributes #[[ZT0_INOUT]] = {{{.*}} "aarch64_inout_zt0" {{.*}}}
56+
// CHECK: attributes #[[ZT0_PRESERVED]] = {{{.*}} "aarch64_preserves_zt0" {{.*}}}
57+
// CHECK: attributes #[[ZT0_NEW]] = {{{.*}} "aarch64_new_zt0" {{.*}}}

clang/test/Sema/aarch64-sme-func-attrs-without-target-feature.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ void shared_za_def() __arm_inout("za") { } // expected-error {{function using ZA
88
__arm_new("za") void new_za_def() { } // expected-error {{function using ZA state requires 'sme'}}
99
__arm_locally_streaming void locally_streaming_def() { } // expected-error {{function executed in streaming-SVE mode requires 'sme'}}
1010
void streaming_shared_za_def() __arm_streaming __arm_inout("za") { } // expected-error {{function executed in streaming-SVE mode requires 'sme'}}
11+
void inout_za_def() __arm_inout("za") { } // expected-error {{function using ZA state requires 'sme'}}
12+
void inout_zt0_def() __arm_inout("zt0") { } // expected-error {{function using ZT0 state requires 'sme2'}}
1113

1214
// It should work fine when we explicitly add the target("sme") attribute.
1315
__attribute__((target("sme"))) void streaming_compatible_def_sme_attr() __arm_streaming_compatible {} // OK

clang/test/Sema/aarch64-sme-func-attrs.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,11 @@ void invalid_arm_in_unknown_state(void) __arm_in("unknownstate");
353353

354354
void valid_state_attrs_in_in1(void) __arm_in("za");
355355
void valid_state_attrs_in_in2(void) __arm_in("za", "za");
356+
void valid_state_attrs_in_in3(void) __arm_in("zt0");
357+
void valid_state_attrs_in_in4(void) __arm_in("zt0", "zt0");
358+
void valid_state_attrs_in_in5(void) __arm_in("za", "zt0");
359+
__arm_new("za") void valid_state_attrs_in_in6(void) __arm_in("zt0");
360+
__arm_new("zt0") void valid_state_attrs_in_in7(void) __arm_in("za");
356361

357362
// expected-cpp-error@+2 {{missing state for '__arm_in'}}
358363
// expected-error@+1 {{missing state for '__arm_in'}}
@@ -400,3 +405,43 @@ void conflicting_state_attrs_preserves_out(void) __arm_preserves("za") __arm_out
400405
// expected-cpp-error@+2 {{conflicting attributes for state 'za'}}
401406
// expected-error@+1 {{conflicting attributes for state 'za'}}
402407
void conflicting_state_attrs_preserves_inout(void) __arm_preserves("za") __arm_inout("za");
408+
409+
// expected-cpp-error@+2 {{conflicting attributes for state 'zt0'}}
410+
// expected-error@+1 {{conflicting attributes for state 'zt0'}}
411+
void conflicting_state_attrs_in_out_zt0(void) __arm_in("zt0") __arm_out("zt0");
412+
// expected-cpp-error@+2 {{conflicting attributes for state 'zt0'}}
413+
// expected-error@+1 {{conflicting attributes for state 'zt0'}}
414+
void conflicting_state_attrs_in_inout_zt0(void) __arm_in("zt0") __arm_inout("zt0");
415+
// expected-cpp-error@+2 {{conflicting attributes for state 'zt0'}}
416+
// expected-error@+1 {{conflicting attributes for state 'zt0'}}
417+
void conflicting_state_attrs_in_preserves_zt0(void) __arm_in("zt0") __arm_preserves("zt0");
418+
419+
// expected-cpp-error@+2 {{conflicting attributes for state 'zt0'}}
420+
// expected-error@+1 {{conflicting attributes for state 'zt0'}}
421+
void conflicting_state_attrs_out_in_zt0(void) __arm_out("zt0") __arm_in("zt0");
422+
// expected-cpp-error@+2 {{conflicting attributes for state 'zt0'}}
423+
// expected-error@+1 {{conflicting attributes for state 'zt0'}}
424+
void conflicting_state_attrs_out_inout_zt0(void) __arm_out("zt0") __arm_inout("zt0");
425+
// expected-cpp-error@+2 {{conflicting attributes for state 'zt0'}}
426+
// expected-error@+1 {{conflicting attributes for state 'zt0'}}
427+
void conflicting_state_attrs_out_preserves_zt0(void) __arm_out("zt0") __arm_preserves("zt0");
428+
429+
// expected-cpp-error@+2 {{conflicting attributes for state 'zt0'}}
430+
// expected-error@+1 {{conflicting attributes for state 'zt0'}}
431+
void conflicting_state_attrs_inout_in_zt0(void) __arm_inout("zt0") __arm_in("zt0");
432+
// expected-cpp-error@+2 {{conflicting attributes for state 'zt0'}}
433+
// expected-error@+1 {{conflicting attributes for state 'zt0'}}
434+
void conflicting_state_attrs_inout_out_zt0(void) __arm_inout("zt0") __arm_out("zt0");
435+
// expected-cpp-error@+2 {{conflicting attributes for state 'zt0'}}
436+
// expected-error@+1 {{conflicting attributes for state 'zt0'}}
437+
void conflicting_state_attrs_inout_preserves_zt0(void) __arm_inout("zt0") __arm_preserves("zt0");
438+
439+
// expected-cpp-error@+2 {{conflicting attributes for state 'zt0'}}
440+
// expected-error@+1 {{conflicting attributes for state 'zt0'}}
441+
void conflicting_state_attrs_preserves_in_zt0(void) __arm_preserves("zt0") __arm_in("zt0");
442+
// expected-cpp-error@+2 {{conflicting attributes for state 'zt0'}}
443+
// expected-error@+1 {{conflicting attributes for state 'zt0'}}
444+
void conflicting_state_attrs_preserves_out_zt0(void) __arm_preserves("zt0") __arm_out("zt0");
445+
// expected-cpp-error@+2 {{conflicting attributes for state 'zt0'}}
446+
// expected-error@+1 {{conflicting attributes for state 'zt0'}}
447+
void conflicting_state_attrs_preserves_inout_zt0(void) __arm_preserves("zt0") __arm_inout("zt0");

0 commit comments

Comments
 (0)