Skip to content

Commit e635774

Browse files
committed
Add new aarch64_zt0_undef attribute
1 parent 68b5f0e commit e635774

File tree

7 files changed

+47
-5
lines changed

7 files changed

+47
-5
lines changed

llvm/lib/IR/Verifier.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -2859,6 +2859,9 @@ void Verifier::visitFunction(const Function &F) {
28592859
Check(!Attrs.hasAttrSomewhere(Attribute::ElementType),
28602860
"Attribute 'elementtype' can only be applied to a callsite.", &F);
28612861

2862+
Check(!Attrs.hasFnAttr("aarch64_zt0_undef"),
2863+
"Attribute 'aarch64_zt0_undef' can only be applied to a callsite.");
2864+
28622865
if (Attrs.hasFnAttr(Attribute::Naked))
28632866
for (const Argument &Arg : F.args())
28642867
Check(Arg.use_empty(), "cannot use argument of naked function", &Arg);

llvm/lib/Target/AArch64/SMEABIPass.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ void emitTPIDR2Save(Module *M, IRBuilder<> &Builder, bool ZT0IsUndef = false) {
6565
CallInst *Call = Builder.CreateCall(Callee);
6666

6767
// If ZT0 is undefined (i.e. we're at the entry of a "new_zt0" function), mark
68-
// __arm_tpidr2_save as preserving ZT0. This prevents an unnecessary spill of
68+
// that on the __arm_tpidr2_save call. This prevents an unnecessary spill of
6969
// ZT0 that can occur before ZA is enabled.
7070
if (ZT0IsUndef)
71-
Call->addFnAttr(Attribute::get(Ctx, "aarch64_preserves_zt0"));
71+
Call->addFnAttr(Attribute::get(Ctx, "aarch64_zt0_undef"));
7272

7373
Call->setCallingConv(
7474
CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X0);

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

+2
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ SMEAttrs::SMEAttrs(const AttributeList &Attrs) {
9595
Bitmask |= encodeZT0State(StateValue::Preserved);
9696
if (Attrs.hasFnAttr("aarch64_new_zt0"))
9797
Bitmask |= encodeZT0State(StateValue::New);
98+
if (Attrs.hasFnAttr("aarch64_zt0_undef"))
99+
Bitmask |= encodeZT0State(StateValue::Undef);
98100
}
99101

100102
bool SMEAttrs::requiresSMChange(const SMEAttrs &Callee) const {

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

+6-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ class SMEAttrs {
3232
Out = 2, // aarch64_out_zt0
3333
InOut = 3, // aarch64_inout_zt0
3434
Preserved = 4, // aarch64_preserves_zt0
35-
New = 5 // aarch64_new_zt0
35+
New = 5, // aarch64_new_zt0
36+
Undef = 6 // aarch64_zt0_undef
3637
};
3738

3839
// Enum with bitmasks for each individual SME feature.
@@ -125,14 +126,17 @@ class SMEAttrs {
125126
bool isPreservesZT0() const {
126127
return decodeZT0State(Bitmask) == StateValue::Preserved;
127128
}
129+
bool isUndefZT0() const {
130+
return decodeZT0State(Bitmask) == StateValue::Undef;
131+
}
128132
bool sharesZT0() const {
129133
StateValue State = decodeZT0State(Bitmask);
130134
return State == StateValue::In || State == StateValue::Out ||
131135
State == StateValue::InOut || State == StateValue::Preserved;
132136
}
133137
bool hasZT0State() const { return isNewZT0() || sharesZT0(); }
134138
bool requiresPreservingZT0(const SMEAttrs &Callee) const {
135-
return hasZT0State() && !Callee.sharesZT0() &&
139+
return hasZT0State() && !Callee.isUndefZT0() && !Callee.sharesZT0() &&
136140
!Callee.hasAgnosticZAInterface();
137141
}
138142
bool requiresDisablingZABeforeCall(const SMEAttrs &Callee) const {

llvm/test/CodeGen/AArch64/sme-new-zt0-function.ll

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ define void @private_za() "aarch64_new_zt0" {
1111
; CHECK: declare void @__arm_tpidr2_save() #[[TPIDR2_SAVE_DECL_ATTR:[0-9]+]]
1212

1313
; CHECK: attributes #[[TPIDR2_SAVE_DECL_ATTR]] = { "aarch64_pstate_sm_compatible" }
14-
; CHECK: attributes #[[TPIDR2_SAVE_CALL_ATTR]] = { "aarch64_preserves_zt0" }
14+
; CHECK: attributes #[[TPIDR2_SAVE_CALL_ATTR]] = { "aarch64_zt0_undef" }

llvm/test/Verifier/sme-attributes.ll

+3
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,6 @@ declare void @zt0_inout_out() "aarch64_inout_zt0" "aarch64_out_zt0";
6868

6969
declare void @zt0_inout_agnostic() "aarch64_inout_zt0" "aarch64_za_state_agnostic";
7070
; CHECK: Attributes 'aarch64_new_zt0', 'aarch64_in_zt0', 'aarch64_out_zt0', 'aarch64_inout_zt0', 'aarch64_preserves_zt0' and 'aarch64_za_state_agnostic' are mutually exclusive
71+
72+
declare void @zt0_undef_function() "aarch64_zt0_undef";
73+
; CHECK: Attribute 'aarch64_zt0_undef' can only be applied to a callsite.

llvm/unittests/Target/AArch64/SMEAttributesTest.cpp

+30
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "Utils/AArch64SMEAttributes.h"
22
#include "llvm/AsmParser/Parser.h"
33
#include "llvm/IR/Function.h"
4+
#include "llvm/IR/InstrTypes.h"
45
#include "llvm/IR/Module.h"
56
#include "llvm/Support/SourceMgr.h"
67

@@ -69,6 +70,15 @@ TEST(SMEAttributes, Constructors) {
6970
ASSERT_TRUE(SA(*parseIR("declare void @foo() \"aarch64_new_zt0\"")
7071
->getFunction("foo"))
7172
.isNewZT0());
73+
ASSERT_TRUE(
74+
SA(cast<CallBase>((parseIR("declare void @callee()\n"
75+
"define void @foo() {"
76+
"call void @callee() \"aarch64_zt0_undef\"\n"
77+
"ret void\n}")
78+
->getFunction("foo")
79+
->begin()
80+
->front())))
81+
.isUndefZT0());
7282

7383
// Invalid combinations.
7484
EXPECT_DEBUG_DEATH(SA(SA::SM_Enabled | SA::SM_Compatible),
@@ -215,6 +225,18 @@ TEST(SMEAttributes, Basics) {
215225
ASSERT_FALSE(ZT0_New.hasSharedZAInterface());
216226
ASSERT_TRUE(ZT0_New.hasPrivateZAInterface());
217227

228+
SA ZT0_Undef = SA(SA::encodeZT0State(SA::StateValue::Undef));
229+
ASSERT_FALSE(ZT0_Undef.isNewZT0());
230+
ASSERT_FALSE(ZT0_Undef.isInZT0());
231+
ASSERT_FALSE(ZT0_Undef.isOutZT0());
232+
ASSERT_FALSE(ZT0_Undef.isInOutZT0());
233+
ASSERT_FALSE(ZT0_Undef.isPreservesZT0());
234+
ASSERT_FALSE(ZT0_Undef.sharesZT0());
235+
ASSERT_FALSE(ZT0_Undef.hasZT0State());
236+
ASSERT_FALSE(ZT0_Undef.hasSharedZAInterface());
237+
ASSERT_TRUE(ZT0_Undef.hasPrivateZAInterface());
238+
ASSERT_TRUE(ZT0_Undef.isUndefZT0());
239+
218240
ASSERT_FALSE(SA(SA::Normal).isInZT0());
219241
ASSERT_FALSE(SA(SA::Normal).isOutZT0());
220242
ASSERT_FALSE(SA(SA::Normal).isInOutZT0());
@@ -285,6 +307,7 @@ TEST(SMEAttributes, Transitions) {
285307
SA ZT0_Shared = SA(SA::encodeZT0State(SA::StateValue::In));
286308
SA ZA_ZT0_Shared = SA(SA::encodeZAState(SA::StateValue::In) |
287309
SA::encodeZT0State(SA::StateValue::In));
310+
SA Undef_ZT0 = SA((SA::encodeZT0State(SA::StateValue::Undef)));
288311

289312
// Shared ZA -> Private ZA Interface
290313
ASSERT_FALSE(ZA_Shared.requiresDisablingZABeforeCall(Private_ZA));
@@ -295,6 +318,13 @@ TEST(SMEAttributes, Transitions) {
295318
ASSERT_TRUE(ZT0_Shared.requiresPreservingZT0(Private_ZA));
296319
ASSERT_TRUE(ZT0_Shared.requiresEnablingZAAfterCall(Private_ZA));
297320

321+
// Shared Undef ZT0 -> Private ZA Interface
322+
// Note: "Undef ZT0" is a callsite attribute that means ZT0 is undefined at
323+
// point the of the call.
324+
ASSERT_TRUE(ZT0_Shared.requiresDisablingZABeforeCall(Undef_ZT0));
325+
ASSERT_FALSE(ZT0_Shared.requiresPreservingZT0(Undef_ZT0));
326+
ASSERT_TRUE(ZT0_Shared.requiresEnablingZAAfterCall(Undef_ZT0));
327+
298328
// Shared ZA & ZT0 -> Private ZA Interface
299329
ASSERT_FALSE(ZA_ZT0_Shared.requiresDisablingZABeforeCall(Private_ZA));
300330
ASSERT_TRUE(ZA_ZT0_Shared.requiresPreservingZT0(Private_ZA));

0 commit comments

Comments
 (0)