xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/AArch64/Utils/AArch64SMEAttributes.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1bdd1243dSDimitry Andric //===-- AArch64SMEAttributes.h - Helper for interpreting SME attributes -*-===//
2bdd1243dSDimitry Andric //
3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bdd1243dSDimitry Andric //
7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
8bdd1243dSDimitry Andric 
9bdd1243dSDimitry Andric #ifndef LLVM_LIB_TARGET_AARCH64_UTILS_AARCH64SMEATTRIBUTES_H
10bdd1243dSDimitry Andric #define LLVM_LIB_TARGET_AARCH64_UTILS_AARCH64SMEATTRIBUTES_H
1106c3fb27SDimitry Andric 
1206c3fb27SDimitry Andric #include "llvm/IR/Function.h"
1306c3fb27SDimitry Andric 
14bdd1243dSDimitry Andric namespace llvm {
15bdd1243dSDimitry Andric 
16bdd1243dSDimitry Andric class Function;
17bdd1243dSDimitry Andric class CallBase;
18bdd1243dSDimitry Andric class AttributeList;
19bdd1243dSDimitry Andric 
20bdd1243dSDimitry Andric /// SMEAttrs is a utility class to parse the SME ACLE attributes on functions.
21bdd1243dSDimitry Andric /// It helps determine a function's requirements for PSTATE.ZA and PSTATE.SM. It
22bdd1243dSDimitry Andric /// has interfaces to query whether a streaming mode change or lazy-save
23bdd1243dSDimitry Andric /// mechanism is required when going from one function to another (e.g. through
24bdd1243dSDimitry Andric /// a call).
25bdd1243dSDimitry Andric class SMEAttrs {
26bdd1243dSDimitry Andric   unsigned Bitmask;
27bdd1243dSDimitry Andric 
28bdd1243dSDimitry Andric public:
297a6dacacSDimitry Andric   enum class StateValue {
307a6dacacSDimitry Andric     None = 0,
317a6dacacSDimitry Andric     In = 1,        // aarch64_in_zt0
327a6dacacSDimitry Andric     Out = 2,       // aarch64_out_zt0
337a6dacacSDimitry Andric     InOut = 3,     // aarch64_inout_zt0
347a6dacacSDimitry Andric     Preserved = 4, // aarch64_preserves_zt0
357a6dacacSDimitry Andric     New = 5        // aarch64_new_zt0
367a6dacacSDimitry Andric   };
377a6dacacSDimitry Andric 
38bdd1243dSDimitry Andric   // Enum with bitmasks for each individual SME feature.
39bdd1243dSDimitry Andric   enum Mask {
40bdd1243dSDimitry Andric     Normal = 0,
41bdd1243dSDimitry Andric     SM_Enabled = 1 << 0,      // aarch64_pstate_sm_enabled
42bdd1243dSDimitry Andric     SM_Compatible = 1 << 1,   // aarch64_pstate_sm_compatible
4306c3fb27SDimitry Andric     SM_Body = 1 << 2,         // aarch64_pstate_sm_body
44*0fca6ea1SDimitry Andric     SME_ABI_Routine = 1 << 3, // Used for SME ABI routines to avoid lazy saves
45*0fca6ea1SDimitry Andric     ZA_Shift = 4,
46*0fca6ea1SDimitry Andric     ZA_Mask = 0b111 << ZA_Shift,
477a6dacacSDimitry Andric     ZT0_Shift = 7,
487a6dacacSDimitry Andric     ZT0_Mask = 0b111 << ZT0_Shift
49bdd1243dSDimitry Andric   };
50bdd1243dSDimitry Andric 
51bdd1243dSDimitry Andric   SMEAttrs(unsigned Mask = Normal) : Bitmask(0) { set(Mask); }
52bdd1243dSDimitry Andric   SMEAttrs(const Function &F) : SMEAttrs(F.getAttributes()) {}
53bdd1243dSDimitry Andric   SMEAttrs(const CallBase &CB);
54bdd1243dSDimitry Andric   SMEAttrs(const AttributeList &L);
555f757f3fSDimitry Andric   SMEAttrs(StringRef FuncName);
56bdd1243dSDimitry Andric 
57bdd1243dSDimitry Andric   void set(unsigned M, bool Enable = true);
58bdd1243dSDimitry Andric 
59bdd1243dSDimitry Andric   // Interfaces to query PSTATE.SM
60bdd1243dSDimitry Andric   bool hasStreamingBody() const { return Bitmask & SM_Body; }
61bdd1243dSDimitry Andric   bool hasStreamingInterface() const { return Bitmask & SM_Enabled; }
62bdd1243dSDimitry Andric   bool hasStreamingInterfaceOrBody() const {
63bdd1243dSDimitry Andric     return hasStreamingBody() || hasStreamingInterface();
64bdd1243dSDimitry Andric   }
65bdd1243dSDimitry Andric   bool hasStreamingCompatibleInterface() const {
66bdd1243dSDimitry Andric     return Bitmask & SM_Compatible;
67bdd1243dSDimitry Andric   }
68bdd1243dSDimitry Andric   bool hasNonStreamingInterface() const {
69bdd1243dSDimitry Andric     return !hasStreamingInterface() && !hasStreamingCompatibleInterface();
70bdd1243dSDimitry Andric   }
71bdd1243dSDimitry Andric   bool hasNonStreamingInterfaceAndBody() const {
72bdd1243dSDimitry Andric     return hasNonStreamingInterface() && !hasStreamingBody();
73bdd1243dSDimitry Andric   }
74bdd1243dSDimitry Andric 
75bdd1243dSDimitry Andric   /// \return true if a call from Caller -> Callee requires a change in
76bdd1243dSDimitry Andric   /// streaming mode.
777a6dacacSDimitry Andric   bool requiresSMChange(const SMEAttrs &Callee) const;
78bdd1243dSDimitry Andric 
79*0fca6ea1SDimitry Andric   // Interfaces to query ZA
80*0fca6ea1SDimitry Andric   static StateValue decodeZAState(unsigned Bitmask) {
81*0fca6ea1SDimitry Andric     return static_cast<StateValue>((Bitmask & ZA_Mask) >> ZA_Shift);
82*0fca6ea1SDimitry Andric   }
83*0fca6ea1SDimitry Andric   static unsigned encodeZAState(StateValue S) {
84*0fca6ea1SDimitry Andric     return static_cast<unsigned>(S) << ZA_Shift;
85*0fca6ea1SDimitry Andric   }
86*0fca6ea1SDimitry Andric 
87*0fca6ea1SDimitry Andric   bool isNewZA() const { return decodeZAState(Bitmask) == StateValue::New; }
88*0fca6ea1SDimitry Andric   bool isInZA() const { return decodeZAState(Bitmask) == StateValue::In; }
89*0fca6ea1SDimitry Andric   bool isOutZA() const { return decodeZAState(Bitmask) == StateValue::Out; }
90*0fca6ea1SDimitry Andric   bool isInOutZA() const { return decodeZAState(Bitmask) == StateValue::InOut; }
91*0fca6ea1SDimitry Andric   bool isPreservesZA() const {
92*0fca6ea1SDimitry Andric     return decodeZAState(Bitmask) == StateValue::Preserved;
93*0fca6ea1SDimitry Andric   }
94*0fca6ea1SDimitry Andric   bool sharesZA() const {
95*0fca6ea1SDimitry Andric     StateValue State = decodeZAState(Bitmask);
96*0fca6ea1SDimitry Andric     return State == StateValue::In || State == StateValue::Out ||
97*0fca6ea1SDimitry Andric            State == StateValue::InOut || State == StateValue::Preserved;
98*0fca6ea1SDimitry Andric   }
997a6dacacSDimitry Andric   bool hasSharedZAInterface() const { return sharesZA() || sharesZT0(); }
100bdd1243dSDimitry Andric   bool hasPrivateZAInterface() const { return !hasSharedZAInterface(); }
101*0fca6ea1SDimitry Andric   bool hasZAState() const { return isNewZA() || sharesZA(); }
102bdd1243dSDimitry Andric   bool requiresLazySave(const SMEAttrs &Callee) const {
103bdd1243dSDimitry Andric     return hasZAState() && Callee.hasPrivateZAInterface() &&
1047a6dacacSDimitry Andric            !(Callee.Bitmask & SME_ABI_Routine);
1057a6dacacSDimitry Andric   }
1067a6dacacSDimitry Andric 
1077a6dacacSDimitry Andric   // Interfaces to query ZT0 State
1087a6dacacSDimitry Andric   static StateValue decodeZT0State(unsigned Bitmask) {
1097a6dacacSDimitry Andric     return static_cast<StateValue>((Bitmask & ZT0_Mask) >> ZT0_Shift);
1107a6dacacSDimitry Andric   }
1117a6dacacSDimitry Andric   static unsigned encodeZT0State(StateValue S) {
1127a6dacacSDimitry Andric     return static_cast<unsigned>(S) << ZT0_Shift;
1137a6dacacSDimitry Andric   }
1147a6dacacSDimitry Andric 
1157a6dacacSDimitry Andric   bool isNewZT0() const { return decodeZT0State(Bitmask) == StateValue::New; }
1167a6dacacSDimitry Andric   bool isInZT0() const { return decodeZT0State(Bitmask) == StateValue::In; }
1177a6dacacSDimitry Andric   bool isOutZT0() const { return decodeZT0State(Bitmask) == StateValue::Out; }
1187a6dacacSDimitry Andric   bool isInOutZT0() const {
1197a6dacacSDimitry Andric     return decodeZT0State(Bitmask) == StateValue::InOut;
1207a6dacacSDimitry Andric   }
1217a6dacacSDimitry Andric   bool isPreservesZT0() const {
1227a6dacacSDimitry Andric     return decodeZT0State(Bitmask) == StateValue::Preserved;
1237a6dacacSDimitry Andric   }
1247a6dacacSDimitry Andric   bool sharesZT0() const {
1257a6dacacSDimitry Andric     StateValue State = decodeZT0State(Bitmask);
1267a6dacacSDimitry Andric     return State == StateValue::In || State == StateValue::Out ||
1277a6dacacSDimitry Andric            State == StateValue::InOut || State == StateValue::Preserved;
1287a6dacacSDimitry Andric   }
1297a6dacacSDimitry Andric   bool hasZT0State() const { return isNewZT0() || sharesZT0(); }
1307a6dacacSDimitry Andric   bool requiresPreservingZT0(const SMEAttrs &Callee) const {
1317a6dacacSDimitry Andric     return hasZT0State() && !Callee.sharesZT0();
1327a6dacacSDimitry Andric   }
1337a6dacacSDimitry Andric   bool requiresDisablingZABeforeCall(const SMEAttrs &Callee) const {
1347a6dacacSDimitry Andric     return hasZT0State() && !hasZAState() && Callee.hasPrivateZAInterface() &&
1357a6dacacSDimitry Andric            !(Callee.Bitmask & SME_ABI_Routine);
1367a6dacacSDimitry Andric   }
1377a6dacacSDimitry Andric   bool requiresEnablingZAAfterCall(const SMEAttrs &Callee) const {
1387a6dacacSDimitry Andric     return requiresLazySave(Callee) || requiresDisablingZABeforeCall(Callee);
139bdd1243dSDimitry Andric   }
140bdd1243dSDimitry Andric };
141bdd1243dSDimitry Andric 
142bdd1243dSDimitry Andric } // namespace llvm
143bdd1243dSDimitry Andric 
144bdd1243dSDimitry Andric #endif // LLVM_LIB_TARGET_AARCH64_UTILS_AARCH64SMEATTRIBUTES_H
145