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