xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AArch64/Utils/AArch64SMEAttributes.h (revision b64c5a0ace59af62eff52bfe110a521dc73c937b)
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 
14 namespace llvm {
15 
16 class Function;
17 class CallBase;
18 class 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).
25 class SMEAttrs {
26   unsigned Bitmask;
27 
28 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 
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(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