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     ZA_Shared = 1 << 3,       // aarch64_pstate_sm_shared
45     ZA_New = 1 << 4,          // aarch64_pstate_sm_new
46     ZA_Preserved = 1 << 5,    // aarch64_pstate_sm_preserved
47     SME_ABI_Routine = 1 << 6, // Used for SME ABI routines to avoid lazy saves
48     ZT0_Shift = 7,
49     ZT0_Mask = 0b111 << ZT0_Shift
50   };
51 
52   SMEAttrs(unsigned Mask = Normal) : Bitmask(0) { set(Mask); }
SMEAttrs(const Function & F)53   SMEAttrs(const Function &F) : SMEAttrs(F.getAttributes()) {}
54   SMEAttrs(const CallBase &CB);
55   SMEAttrs(const AttributeList &L);
56   SMEAttrs(StringRef FuncName);
57 
58   void set(unsigned M, bool Enable = true);
59 
60   // Interfaces to query PSTATE.SM
hasStreamingBody()61   bool hasStreamingBody() const { return Bitmask & SM_Body; }
hasStreamingInterface()62   bool hasStreamingInterface() const { return Bitmask & SM_Enabled; }
hasStreamingInterfaceOrBody()63   bool hasStreamingInterfaceOrBody() const {
64     return hasStreamingBody() || hasStreamingInterface();
65   }
hasStreamingCompatibleInterface()66   bool hasStreamingCompatibleInterface() const {
67     return Bitmask & SM_Compatible;
68   }
hasNonStreamingInterface()69   bool hasNonStreamingInterface() const {
70     return !hasStreamingInterface() && !hasStreamingCompatibleInterface();
71   }
hasNonStreamingInterfaceAndBody()72   bool hasNonStreamingInterfaceAndBody() const {
73     return hasNonStreamingInterface() && !hasStreamingBody();
74   }
75 
76   /// \return true if a call from Caller -> Callee requires a change in
77   /// streaming mode.
78   bool requiresSMChange(const SMEAttrs &Callee) const;
79 
80   // Interfaces to query PSTATE.ZA
hasNewZABody()81   bool hasNewZABody() const { return Bitmask & ZA_New; }
sharesZA()82   bool sharesZA() const { return Bitmask & ZA_Shared; }
hasSharedZAInterface()83   bool hasSharedZAInterface() const { return sharesZA() || sharesZT0(); }
hasPrivateZAInterface()84   bool hasPrivateZAInterface() const { return !hasSharedZAInterface(); }
preservesZA()85   bool preservesZA() const { return Bitmask & ZA_Preserved; }
hasZAState()86   bool hasZAState() const { return hasNewZABody() || sharesZA(); }
requiresLazySave(const SMEAttrs & Callee)87   bool requiresLazySave(const SMEAttrs &Callee) const {
88     return hasZAState() && Callee.hasPrivateZAInterface() &&
89            !(Callee.Bitmask & SME_ABI_Routine);
90   }
91 
92   // Interfaces to query ZT0 State
decodeZT0State(unsigned Bitmask)93   static StateValue decodeZT0State(unsigned Bitmask) {
94     return static_cast<StateValue>((Bitmask & ZT0_Mask) >> ZT0_Shift);
95   }
encodeZT0State(StateValue S)96   static unsigned encodeZT0State(StateValue S) {
97     return static_cast<unsigned>(S) << ZT0_Shift;
98   }
99 
isNewZT0()100   bool isNewZT0() const { return decodeZT0State(Bitmask) == StateValue::New; }
isInZT0()101   bool isInZT0() const { return decodeZT0State(Bitmask) == StateValue::In; }
isOutZT0()102   bool isOutZT0() const { return decodeZT0State(Bitmask) == StateValue::Out; }
isInOutZT0()103   bool isInOutZT0() const {
104     return decodeZT0State(Bitmask) == StateValue::InOut;
105   }
isPreservesZT0()106   bool isPreservesZT0() const {
107     return decodeZT0State(Bitmask) == StateValue::Preserved;
108   }
sharesZT0()109   bool sharesZT0() const {
110     StateValue State = decodeZT0State(Bitmask);
111     return State == StateValue::In || State == StateValue::Out ||
112            State == StateValue::InOut || State == StateValue::Preserved;
113   }
hasZT0State()114   bool hasZT0State() const { return isNewZT0() || sharesZT0(); }
requiresPreservingZT0(const SMEAttrs & Callee)115   bool requiresPreservingZT0(const SMEAttrs &Callee) const {
116     return hasZT0State() && !Callee.sharesZT0();
117   }
requiresDisablingZABeforeCall(const SMEAttrs & Callee)118   bool requiresDisablingZABeforeCall(const SMEAttrs &Callee) const {
119     return hasZT0State() && !hasZAState() && Callee.hasPrivateZAInterface() &&
120            !(Callee.Bitmask & SME_ABI_Routine);
121   }
requiresEnablingZAAfterCall(const SMEAttrs & Callee)122   bool requiresEnablingZAAfterCall(const SMEAttrs &Callee) const {
123     return requiresLazySave(Callee) || requiresDisablingZABeforeCall(Callee);
124   }
125 };
126 
127 } // namespace llvm
128 
129 #endif // LLVM_LIB_TARGET_AARCH64_UTILS_AARCH64SMEATTRIBUTES_H
130