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