Skip to content

Commit a4ec04e

Browse files
[AArch64][SME2] Add ZT0 attributes to SMEAttrs (#77607)
This patch extends SMEAttrs to interpret the following new attributes, which are mutually exclusive and apply to SME2 only: - aarch64_sme_zt0_in (ZT0_In) - aarch64_sme_zt0_out (ZT0_Out) - aarch64_sme_zt0_inout (ZT0_InOut) - aarch64_sme_zt0_new (ZT0_New) - aarch64_sme_zt0_preserved (ZT0_Preserved) ZT0_In, ZT0_Out, ZT0_InOut & ZT0_Preserved are all considered to share ZT0. These attributes will be required by later patches to determine if ZT0 should be preserved around function calls, or cleared on entry to the function.
1 parent f1f1875 commit a4ec04e

File tree

5 files changed

+190
-7
lines changed

5 files changed

+190
-7
lines changed

llvm/lib/IR/Verifier.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2161,6 +2161,15 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
21612161
V);
21622162
}
21632163

2164+
Check(
2165+
(Attrs.hasFnAttr("aarch64_new_zt0") + Attrs.hasFnAttr("aarch64_in_zt0") +
2166+
Attrs.hasFnAttr("aarch64_inout_zt0") +
2167+
Attrs.hasFnAttr("aarch64_out_zt0") +
2168+
Attrs.hasFnAttr("aarch64_preserves_zt0")) <= 1,
2169+
"Attributes 'aarch64_new_zt0', 'aarch64_in_zt0', 'aarch64_out_zt0', "
2170+
"'aarch64_inout_zt0' and 'aarch64_preserves_zt0' are mutually exclusive",
2171+
V);
2172+
21642173
if (Attrs.hasFnAttr(Attribute::JumpTable)) {
21652174
const GlobalValue *GV = cast<GlobalValue>(V);
21662175
Check(GV->hasGlobalUnnamedAddr(),

llvm/lib/Target/AArch64/Utils/AArch64SMEAttributes.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,26 @@ void SMEAttrs::set(unsigned M, bool Enable) {
1818
else
1919
Bitmask &= ~M;
2020

21+
// Streaming Mode Attrs
2122
assert(!(hasStreamingInterface() && hasStreamingCompatibleInterface()) &&
2223
"SM_Enabled and SM_Compatible are mutually exclusive");
23-
assert(!(hasNewZABody() && hasSharedZAInterface()) &&
24+
25+
// ZA Attrs
26+
assert(!(hasNewZABody() && sharesZA()) &&
2427
"ZA_New and ZA_Shared are mutually exclusive");
2528
assert(!(hasNewZABody() && preservesZA()) &&
2629
"ZA_New and ZA_Preserved are mutually exclusive");
2730
assert(!(hasNewZABody() && (Bitmask & ZA_NoLazySave)) &&
2831
"ZA_New and ZA_NoLazySave are mutually exclusive");
29-
assert(!(hasSharedZAInterface() && (Bitmask & ZA_NoLazySave)) &&
32+
assert(!(sharesZA() && (Bitmask & ZA_NoLazySave)) &&
3033
"ZA_Shared and ZA_NoLazySave are mutually exclusive");
34+
35+
// ZT0 Attrs
36+
assert(
37+
(!sharesZT0() || (isNewZT0() ^ isInZT0() ^ isInOutZT0() ^ isOutZT0() ^
38+
isPreservesZT0())) &&
39+
"Attributes 'aarch64_new_zt0', 'aarch64_in_zt0', 'aarch64_out_zt0', "
40+
"'aarch64_inout_zt0' and 'aarch64_preserves_zt0' are mutually exclusive");
3141
}
3242

3343
SMEAttrs::SMEAttrs(const CallBase &CB) {
@@ -60,6 +70,16 @@ SMEAttrs::SMEAttrs(const AttributeList &Attrs) {
6070
Bitmask |= ZA_New;
6171
if (Attrs.hasFnAttr("aarch64_pstate_za_preserved"))
6272
Bitmask |= ZA_Preserved;
73+
if (Attrs.hasFnAttr("aarch64_in_zt0"))
74+
Bitmask |= encodeZT0State(StateValue::In);
75+
if (Attrs.hasFnAttr("aarch64_out_zt0"))
76+
Bitmask |= encodeZT0State(StateValue::Out);
77+
if (Attrs.hasFnAttr("aarch64_inout_zt0"))
78+
Bitmask |= encodeZT0State(StateValue::InOut);
79+
if (Attrs.hasFnAttr("aarch64_preserves_zt0"))
80+
Bitmask |= encodeZT0State(StateValue::Preserved);
81+
if (Attrs.hasFnAttr("aarch64_new_zt0"))
82+
Bitmask |= encodeZT0State(StateValue::New);
6383
}
6484

6585
std::optional<bool>

llvm/lib/Target/AArch64/Utils/AArch64SMEAttributes.h

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ class SMEAttrs {
2626
unsigned Bitmask;
2727

2828
public:
29+
enum class StateValue {
30+
None = 0,
31+
In = 1, // aarch64_in_zt0
32+
Out = 2, // aarch64_out_zt0
33+
InOut = 3, // aarch64_inout_zt0
34+
Preserved = 4, // aarch64_preserves_zt0
35+
New = 5 // aarch64_new_zt0
36+
};
37+
2938
// Enum with bitmasks for each individual SME feature.
3039
enum Mask {
3140
Normal = 0,
@@ -36,7 +45,8 @@ class SMEAttrs {
3645
ZA_New = 1 << 4, // aarch64_pstate_sm_new
3746
ZA_Preserved = 1 << 5, // aarch64_pstate_sm_preserved
3847
ZA_NoLazySave = 1 << 6, // Used for SME ABI routines to avoid lazy saves
39-
All = ZA_Preserved - 1
48+
ZT0_Shift = 7,
49+
ZT0_Mask = 0b111 << ZT0_Shift
4050
};
4151

4252
SMEAttrs(unsigned Mask = Normal) : Bitmask(0) { set(Mask); }
@@ -76,16 +86,39 @@ class SMEAttrs {
7686

7787
// Interfaces to query PSTATE.ZA
7888
bool hasNewZABody() const { return Bitmask & ZA_New; }
79-
bool hasSharedZAInterface() const { return Bitmask & ZA_Shared; }
89+
bool sharesZA() const { return Bitmask & ZA_Shared; }
90+
bool hasSharedZAInterface() const { return sharesZA() || sharesZT0(); }
8091
bool hasPrivateZAInterface() const { return !hasSharedZAInterface(); }
8192
bool preservesZA() const { return Bitmask & ZA_Preserved; }
82-
bool hasZAState() const {
83-
return hasNewZABody() || hasSharedZAInterface();
84-
}
93+
bool hasZAState() const { return hasNewZABody() || sharesZA(); }
8594
bool requiresLazySave(const SMEAttrs &Callee) const {
8695
return hasZAState() && Callee.hasPrivateZAInterface() &&
8796
!(Callee.Bitmask & ZA_NoLazySave);
8897
}
98+
99+
// Interfaces to query ZT0 State
100+
static StateValue decodeZT0State(unsigned Bitmask) {
101+
return static_cast<StateValue>((Bitmask & ZT0_Mask) >> ZT0_Shift);
102+
}
103+
static unsigned encodeZT0State(StateValue S) {
104+
return static_cast<unsigned>(S) << ZT0_Shift;
105+
}
106+
107+
bool isNewZT0() const { return decodeZT0State(Bitmask) == StateValue::New; }
108+
bool isInZT0() const { return decodeZT0State(Bitmask) == StateValue::In; }
109+
bool isOutZT0() const { return decodeZT0State(Bitmask) == StateValue::Out; }
110+
bool isInOutZT0() const {
111+
return decodeZT0State(Bitmask) == StateValue::InOut;
112+
}
113+
bool isPreservesZT0() const {
114+
return decodeZT0State(Bitmask) == StateValue::Preserved;
115+
}
116+
bool sharesZT0() const {
117+
StateValue State = decodeZT0State(Bitmask);
118+
return State == StateValue::In || State == StateValue::Out ||
119+
State == StateValue::InOut || State == StateValue::Preserved;
120+
}
121+
bool hasZT0State() const { return isNewZT0() || sharesZT0(); }
89122
};
90123

91124
} // namespace llvm

llvm/test/Verifier/sme-attributes.ll

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,33 @@ declare void @za_preserved() "aarch64_pstate_za_new" "aarch64_pstate_za_preserve
88

99
declare void @za_shared() "aarch64_pstate_za_new" "aarch64_pstate_za_shared";
1010
; CHECK: Attributes 'aarch64_pstate_za_new and aarch64_pstate_za_shared' are incompatible!
11+
12+
declare void @zt0_new_preserved() "aarch64_new_zt0" "aarch64_preserves_zt0";
13+
; CHECK: Attributes 'aarch64_new_zt0', 'aarch64_in_zt0', 'aarch64_out_zt0', 'aarch64_inout_zt0' and 'aarch64_preserves_zt0' are mutually exclusive
14+
15+
declare void @zt0_new_in() "aarch64_new_zt0" "aarch64_in_zt0";
16+
; CHECK: Attributes 'aarch64_new_zt0', 'aarch64_in_zt0', 'aarch64_out_zt0', 'aarch64_inout_zt0' and 'aarch64_preserves_zt0' are mutually exclusive
17+
18+
declare void @zt0_new_inout() "aarch64_new_zt0" "aarch64_inout_zt0";
19+
; CHECK: Attributes 'aarch64_new_zt0', 'aarch64_in_zt0', 'aarch64_out_zt0', 'aarch64_inout_zt0' and 'aarch64_preserves_zt0' are mutually exclusive
20+
21+
declare void @zt0_new_out() "aarch64_new_zt0" "aarch64_out_zt0";
22+
; CHECK: Attributes 'aarch64_new_zt0', 'aarch64_in_zt0', 'aarch64_out_zt0', 'aarch64_inout_zt0' and 'aarch64_preserves_zt0' are mutually exclusive
23+
24+
declare void @zt0_preserved_in() "aarch64_preserves_zt0" "aarch64_in_zt0";
25+
; CHECK: Attributes 'aarch64_new_zt0', 'aarch64_in_zt0', 'aarch64_out_zt0', 'aarch64_inout_zt0' and 'aarch64_preserves_zt0' are mutually exclusive
26+
27+
declare void @zt0_preserved_inout() "aarch64_preserves_zt0" "aarch64_inout_zt0";
28+
; CHECK: Attributes 'aarch64_new_zt0', 'aarch64_in_zt0', 'aarch64_out_zt0', 'aarch64_inout_zt0' and 'aarch64_preserves_zt0' are mutually exclusive
29+
30+
declare void @zt0_preserved_out() "aarch64_preserves_zt0" "aarch64_out_zt0";
31+
; CHECK: Attributes 'aarch64_new_zt0', 'aarch64_in_zt0', 'aarch64_out_zt0', 'aarch64_inout_zt0' and 'aarch64_preserves_zt0' are mutually exclusive
32+
33+
declare void @zt0_in_inout() "aarch64_in_zt0" "aarch64_inout_zt0";
34+
; CHECK: Attributes 'aarch64_new_zt0', 'aarch64_in_zt0', 'aarch64_out_zt0', 'aarch64_inout_zt0' and 'aarch64_preserves_zt0' are mutually exclusive
35+
36+
declare void @zt0_in_out() "aarch64_in_zt0" "aarch64_out_zt0";
37+
; CHECK: Attributes 'aarch64_new_zt0', 'aarch64_in_zt0', 'aarch64_out_zt0', 'aarch64_inout_zt0' and 'aarch64_preserves_zt0' are mutually exclusive
38+
39+
declare void @zt0_inout_out() "aarch64_inout_zt0" "aarch64_out_zt0";
40+
; CHECK: Attributes 'aarch64_new_zt0', 'aarch64_in_zt0', 'aarch64_out_zt0', 'aarch64_inout_zt0' and 'aarch64_preserves_zt0' are mutually exclusive

llvm/unittests/Target/AArch64/SMEAttributesTest.cpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ TEST(SMEAttributes, Constructors) {
3838
->getFunction("foo"))
3939
.hasStreamingCompatibleInterface());
4040

41+
ASSERT_TRUE(SA(*parseIR("declare void @foo() \"aarch64_pstate_za_shared\"")
42+
->getFunction("foo"))
43+
.sharesZA());
44+
4145
ASSERT_TRUE(SA(*parseIR("declare void @foo() \"aarch64_pstate_za_shared\"")
4246
->getFunction("foo"))
4347
.hasSharedZAInterface());
@@ -50,6 +54,22 @@ TEST(SMEAttributes, Constructors) {
5054
->getFunction("foo"))
5155
.preservesZA());
5256

57+
ASSERT_TRUE(
58+
SA(*parseIR("declare void @foo() \"aarch64_in_zt0\"")->getFunction("foo"))
59+
.isInZT0());
60+
ASSERT_TRUE(SA(*parseIR("declare void @foo() \"aarch64_out_zt0\"")
61+
->getFunction("foo"))
62+
.isOutZT0());
63+
ASSERT_TRUE(SA(*parseIR("declare void @foo() \"aarch64_inout_zt0\"")
64+
->getFunction("foo"))
65+
.isInOutZT0());
66+
ASSERT_TRUE(SA(*parseIR("declare void @foo() \"aarch64_preserves_zt0\"")
67+
->getFunction("foo"))
68+
.isPreservesZT0());
69+
ASSERT_TRUE(SA(*parseIR("declare void @foo() \"aarch64_new_zt0\"")
70+
->getFunction("foo"))
71+
.isNewZT0());
72+
5373
// Invalid combinations.
5474
EXPECT_DEBUG_DEATH(SA(SA::SM_Enabled | SA::SM_Compatible),
5575
"SM_Enabled and SM_Compatible are mutually exclusive");
@@ -82,19 +102,90 @@ TEST(SMEAttributes, Basics) {
82102
// Test PSTATE.ZA interfaces.
83103
ASSERT_FALSE(SA(SA::ZA_Shared).hasPrivateZAInterface());
84104
ASSERT_TRUE(SA(SA::ZA_Shared).hasSharedZAInterface());
105+
ASSERT_TRUE(SA(SA::ZA_Shared).sharesZA());
85106
ASSERT_TRUE(SA(SA::ZA_Shared).hasZAState());
86107
ASSERT_FALSE(SA(SA::ZA_Shared).preservesZA());
87108
ASSERT_TRUE(SA(SA::ZA_Shared | SA::ZA_Preserved).preservesZA());
109+
ASSERT_FALSE(SA(SA::ZA_Shared).sharesZT0());
110+
ASSERT_FALSE(SA(SA::ZA_Shared).hasZT0State());
88111

89112
ASSERT_TRUE(SA(SA::ZA_New).hasPrivateZAInterface());
113+
ASSERT_FALSE(SA(SA::ZA_New).hasSharedZAInterface());
90114
ASSERT_TRUE(SA(SA::ZA_New).hasNewZABody());
91115
ASSERT_TRUE(SA(SA::ZA_New).hasZAState());
92116
ASSERT_FALSE(SA(SA::ZA_New).preservesZA());
117+
ASSERT_FALSE(SA(SA::ZA_New).sharesZT0());
118+
ASSERT_FALSE(SA(SA::ZA_New).hasZT0State());
93119

94120
ASSERT_TRUE(SA(SA::Normal).hasPrivateZAInterface());
121+
ASSERT_FALSE(SA(SA::Normal).hasSharedZAInterface());
95122
ASSERT_FALSE(SA(SA::Normal).hasNewZABody());
96123
ASSERT_FALSE(SA(SA::Normal).hasZAState());
97124
ASSERT_FALSE(SA(SA::Normal).preservesZA());
125+
126+
// Test ZT0 State interfaces
127+
SA ZT0_In = SA(SA::encodeZT0State(SA::StateValue::In));
128+
ASSERT_TRUE(ZT0_In.isInZT0());
129+
ASSERT_FALSE(ZT0_In.isOutZT0());
130+
ASSERT_FALSE(ZT0_In.isInOutZT0());
131+
ASSERT_FALSE(ZT0_In.isPreservesZT0());
132+
ASSERT_FALSE(ZT0_In.isNewZT0());
133+
ASSERT_TRUE(ZT0_In.sharesZT0());
134+
ASSERT_TRUE(ZT0_In.hasZT0State());
135+
ASSERT_TRUE(ZT0_In.hasSharedZAInterface());
136+
ASSERT_FALSE(ZT0_In.hasPrivateZAInterface());
137+
138+
SA ZT0_Out = SA(SA::encodeZT0State(SA::StateValue::Out));
139+
ASSERT_TRUE(ZT0_Out.isOutZT0());
140+
ASSERT_FALSE(ZT0_Out.isInZT0());
141+
ASSERT_FALSE(ZT0_Out.isInOutZT0());
142+
ASSERT_FALSE(ZT0_Out.isPreservesZT0());
143+
ASSERT_FALSE(ZT0_Out.isNewZT0());
144+
ASSERT_TRUE(ZT0_Out.sharesZT0());
145+
ASSERT_TRUE(ZT0_Out.hasZT0State());
146+
ASSERT_TRUE(ZT0_Out.hasSharedZAInterface());
147+
ASSERT_FALSE(ZT0_Out.hasPrivateZAInterface());
148+
149+
SA ZT0_InOut = SA(SA::encodeZT0State(SA::StateValue::InOut));
150+
ASSERT_TRUE(ZT0_InOut.isInOutZT0());
151+
ASSERT_FALSE(ZT0_InOut.isInZT0());
152+
ASSERT_FALSE(ZT0_InOut.isOutZT0());
153+
ASSERT_FALSE(ZT0_InOut.isPreservesZT0());
154+
ASSERT_FALSE(ZT0_InOut.isNewZT0());
155+
ASSERT_TRUE(ZT0_InOut.sharesZT0());
156+
ASSERT_TRUE(ZT0_InOut.hasZT0State());
157+
ASSERT_TRUE(ZT0_InOut.hasSharedZAInterface());
158+
ASSERT_FALSE(ZT0_InOut.hasPrivateZAInterface());
159+
160+
SA ZT0_Preserved = SA(SA::encodeZT0State(SA::StateValue::Preserved));
161+
ASSERT_TRUE(ZT0_Preserved.isPreservesZT0());
162+
ASSERT_FALSE(ZT0_Preserved.isInZT0());
163+
ASSERT_FALSE(ZT0_Preserved.isOutZT0());
164+
ASSERT_FALSE(ZT0_Preserved.isInOutZT0());
165+
ASSERT_FALSE(ZT0_Preserved.isNewZT0());
166+
ASSERT_TRUE(ZT0_Preserved.sharesZT0());
167+
ASSERT_TRUE(ZT0_Preserved.hasZT0State());
168+
ASSERT_TRUE(ZT0_Preserved.hasSharedZAInterface());
169+
ASSERT_FALSE(ZT0_Preserved.hasPrivateZAInterface());
170+
171+
SA ZT0_New = SA(SA::encodeZT0State(SA::StateValue::New));
172+
ASSERT_TRUE(ZT0_New.isNewZT0());
173+
ASSERT_FALSE(ZT0_New.isInZT0());
174+
ASSERT_FALSE(ZT0_New.isOutZT0());
175+
ASSERT_FALSE(ZT0_New.isInOutZT0());
176+
ASSERT_FALSE(ZT0_New.isPreservesZT0());
177+
ASSERT_FALSE(ZT0_New.sharesZT0());
178+
ASSERT_TRUE(ZT0_New.hasZT0State());
179+
ASSERT_FALSE(ZT0_New.hasSharedZAInterface());
180+
ASSERT_TRUE(ZT0_New.hasPrivateZAInterface());
181+
182+
ASSERT_FALSE(SA(SA::Normal).isInZT0());
183+
ASSERT_FALSE(SA(SA::Normal).isOutZT0());
184+
ASSERT_FALSE(SA(SA::Normal).isInOutZT0());
185+
ASSERT_FALSE(SA(SA::Normal).isPreservesZT0());
186+
ASSERT_FALSE(SA(SA::Normal).isNewZT0());
187+
ASSERT_FALSE(SA(SA::Normal).sharesZT0());
188+
ASSERT_FALSE(SA(SA::Normal).hasZT0State());
98189
}
99190

100191
TEST(SMEAttributes, Transitions) {

0 commit comments

Comments
 (0)