
Since https://github.com/ARM-software/acle/pull/276 the ACLE defines attributes to better describe the use of a given SME state. Previously the attributes merely described the possibility of it being 'shared' or 'preserved', whereas the new attributes have more semantics and also describe how the data flows through the program. For ZT0 we already had to add new LLVM IR attributes: * aarch64_new_zt0 * aarch64_in_zt0 * aarch64_out_zt0 * aarch64_inout_zt0 * aarch64_preserves_zt0 We have now done the same for ZA, such that we add: * aarch64_new_za (previously `aarch64_pstate_za_new`) * aarch64_in_za (more specific variation of `aarch64_pstate_za_shared`) * aarch64_out_za (more specific variation of `aarch64_pstate_za_shared`) * aarch64_inout_za (more specific variation of `aarch64_pstate_za_shared`) * aarch64_preserves_za (previously `aarch64_pstate_za_shared, aarch64_pstate_za_preserved`) This explicitly removes 'pstate' from the name, because with SME2 and the new ACLE attributes there is a difference between "sharing ZA" (sharing the ZA matrix register with the caller) and "sharing PSTATE.ZA" (sharing either the ZA or ZT0 register, both part of PSTATE.ZA with the caller).
145 lines
5.3 KiB
C++
145 lines
5.3 KiB
C++
//===-- 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
|