1//===-- AArch64SMEAttributes.h - Helper for interpreting SME attributes -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLVM_LIB_TARGET_AARCH64_UTILS_AARCH64SMEATTRIBUTES_H
10#define LLVM_LIB_TARGET_AARCH64_UTILS_AARCH64SMEATTRIBUTES_H
11
12#include "llvm/IR/Function.h"
13
14namespace llvm {
15
16class Function;
17class CallBase;
18class AttributeList;
19
20/// SMEAttrs is a utility class to parse the SME ACLE attributes on functions.
21/// It helps determine a function's requirements for PSTATE.ZA and PSTATE.SM. It
22/// has interfaces to query whether a streaming mode change or lazy-save
23/// mechanism is required when going from one function to another (e.g. through
24/// a call).
25class SMEAttrs {
26 unsigned Bitmask;
27
28public:
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
38 // Enum with bitmasks for each individual SME feature.
39 enum Mask {
40 Normal = 0,
41 SM_Enabled = 1 << 0, // aarch64_pstate_sm_enabled
42 SM_Compatible = 1 << 1, // aarch64_pstate_sm_compatible
43 SM_Body = 1 << 2, // aarch64_pstate_sm_body
44 SME_ABI_Routine = 1 << 3, // Used for SME ABI routines to avoid lazy saves
45 ZA_Shift = 4,
46 ZA_Mask = 0b111 << ZA_Shift,
47 ZT0_Shift = 7,
48 ZT0_Mask = 0b111 << ZT0_Shift
49 };
50
51 SMEAttrs(unsigned Mask = Normal) : Bitmask(0) { set(M: Mask); }
52 SMEAttrs(const Function &F) : SMEAttrs(F.getAttributes()) {}
53 SMEAttrs(const CallBase &CB);
54 SMEAttrs(const AttributeList &L);
55 SMEAttrs(StringRef FuncName);
56
57 void set(unsigned M, bool Enable = true);
58
59 // Interfaces to query PSTATE.SM
60 bool hasStreamingBody() const { return Bitmask & SM_Body; }
61 bool hasStreamingInterface() const { return Bitmask & SM_Enabled; }
62 bool hasStreamingInterfaceOrBody() const {
63 return hasStreamingBody() || hasStreamingInterface();
64 }
65 bool hasStreamingCompatibleInterface() const {
66 return Bitmask & SM_Compatible;
67 }
68 bool hasNonStreamingInterface() const {
69 return !hasStreamingInterface() && !hasStreamingCompatibleInterface();
70 }
71 bool hasNonStreamingInterfaceAndBody() const {
72 return hasNonStreamingInterface() && !hasStreamingBody();
73 }
74
75 /// \return true if a call from Caller -> Callee requires a change in
76 /// streaming mode.
77 bool requiresSMChange(const SMEAttrs &Callee) const;
78
79 // Interfaces to query ZA
80 static StateValue decodeZAState(unsigned Bitmask) {
81 return static_cast<StateValue>((Bitmask & ZA_Mask) >> ZA_Shift);
82 }
83 static unsigned encodeZAState(StateValue S) {
84 return static_cast<unsigned>(S) << ZA_Shift;
85 }
86
87 bool isNewZA() const { return decodeZAState(Bitmask) == StateValue::New; }
88 bool isInZA() const { return decodeZAState(Bitmask) == StateValue::In; }
89 bool isOutZA() const { return decodeZAState(Bitmask) == StateValue::Out; }
90 bool isInOutZA() const { return decodeZAState(Bitmask) == StateValue::InOut; }
91 bool isPreservesZA() const {
92 return decodeZAState(Bitmask) == StateValue::Preserved;
93 }
94 bool sharesZA() const {
95 StateValue State = decodeZAState(Bitmask);
96 return State == StateValue::In || State == StateValue::Out ||
97 State == StateValue::InOut || State == StateValue::Preserved;
98 }
99 bool hasSharedZAInterface() const { return sharesZA() || sharesZT0(); }
100 bool hasPrivateZAInterface() const { return !hasSharedZAInterface(); }
101 bool hasZAState() const { return isNewZA() || sharesZA(); }
102 bool requiresLazySave(const SMEAttrs &Callee) const {
103 return hasZAState() && Callee.hasPrivateZAInterface() &&
104 !(Callee.Bitmask & SME_ABI_Routine);
105 }
106
107 // Interfaces to query ZT0 State
108 static StateValue decodeZT0State(unsigned Bitmask) {
109 return static_cast<StateValue>((Bitmask & ZT0_Mask) >> ZT0_Shift);
110 }
111 static unsigned encodeZT0State(StateValue S) {
112 return static_cast<unsigned>(S) << ZT0_Shift;
113 }
114
115 bool isNewZT0() const { return decodeZT0State(Bitmask) == StateValue::New; }
116 bool isInZT0() const { return decodeZT0State(Bitmask) == StateValue::In; }
117 bool isOutZT0() const { return decodeZT0State(Bitmask) == StateValue::Out; }
118 bool isInOutZT0() const {
119 return decodeZT0State(Bitmask) == StateValue::InOut;
120 }
121 bool isPreservesZT0() const {
122 return decodeZT0State(Bitmask) == StateValue::Preserved;
123 }
124 bool sharesZT0() const {
125 StateValue State = decodeZT0State(Bitmask);
126 return State == StateValue::In || State == StateValue::Out ||
127 State == StateValue::InOut || State == StateValue::Preserved;
128 }
129 bool hasZT0State() const { return isNewZT0() || sharesZT0(); }
130 bool requiresPreservingZT0(const SMEAttrs &Callee) const {
131 return hasZT0State() && !Callee.sharesZT0();
132 }
133 bool requiresDisablingZABeforeCall(const SMEAttrs &Callee) const {
134 return hasZT0State() && !hasZAState() && Callee.hasPrivateZAInterface() &&
135 !(Callee.Bitmask & SME_ABI_Routine);
136 }
137 bool requiresEnablingZAAfterCall(const SMEAttrs &Callee) const {
138 return requiresLazySave(Callee) || requiresDisablingZABeforeCall(Callee);
139 }
140};
141
142} // namespace llvm
143
144#endif // LLVM_LIB_TARGET_AARCH64_UTILS_AARCH64SMEATTRIBUTES_H
145