1//===-- AArch64SMEAttributes.cpp - 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#include "AArch64SMEAttributes.h"
10#include "llvm/IR/InstrTypes.h"
11#include <cassert>
12
13using namespace llvm;
14
15void SMEAttrs::set(unsigned M, bool Enable) {
16 if (Enable)
17 Bitmask |= M;
18 else
19 Bitmask &= ~M;
20
21 // Streaming Mode Attrs
22 assert(!(hasStreamingInterface() && hasStreamingCompatibleInterface()) &&
23 "SM_Enabled and SM_Compatible are mutually exclusive");
24
25 // ZA Attrs
26 assert(!(isNewZA() && (Bitmask & SME_ABI_Routine)) &&
27 "ZA_New and SME_ABI_Routine are mutually exclusive");
28
29 assert(
30 (isNewZA() + isInZA() + isOutZA() + isInOutZA() + isPreservesZA()) <= 1 &&
31 "Attributes 'aarch64_new_za', 'aarch64_in_za', 'aarch64_out_za', "
32 "'aarch64_inout_za' and 'aarch64_preserves_za' are mutually exclusive");
33
34 // ZT0 Attrs
35 assert(
36 (isNewZT0() + isInZT0() + isOutZT0() + isInOutZT0() + isPreservesZT0()) <=
37 1 &&
38 "Attributes 'aarch64_new_zt0', 'aarch64_in_zt0', 'aarch64_out_zt0', "
39 "'aarch64_inout_zt0' and 'aarch64_preserves_zt0' are mutually exclusive");
40
41 assert(!(hasAgnosticZAInterface() && hasSharedZAInterface()) &&
42 "Function cannot have a shared-ZA interface and an agnostic-ZA "
43 "interface");
44}
45
46SMEAttrs::SMEAttrs(const AttributeList &Attrs) {
47 Bitmask = 0;
48 if (Attrs.hasFnAttr(Kind: "aarch64_pstate_sm_enabled"))
49 Bitmask |= SM_Enabled;
50 if (Attrs.hasFnAttr(Kind: "aarch64_pstate_sm_compatible"))
51 Bitmask |= SM_Compatible;
52 if (Attrs.hasFnAttr(Kind: "aarch64_pstate_sm_body"))
53 Bitmask |= SM_Body;
54 if (Attrs.hasFnAttr(Kind: "aarch64_za_state_agnostic"))
55 Bitmask |= ZA_State_Agnostic;
56 if (Attrs.hasFnAttr(Kind: "aarch64_zt0_undef"))
57 Bitmask |= ZT0_Undef;
58 if (Attrs.hasFnAttr(Kind: "aarch64_in_za"))
59 Bitmask |= encodeZAState(S: StateValue::In);
60 if (Attrs.hasFnAttr(Kind: "aarch64_out_za"))
61 Bitmask |= encodeZAState(S: StateValue::Out);
62 if (Attrs.hasFnAttr(Kind: "aarch64_inout_za"))
63 Bitmask |= encodeZAState(S: StateValue::InOut);
64 if (Attrs.hasFnAttr(Kind: "aarch64_preserves_za"))
65 Bitmask |= encodeZAState(S: StateValue::Preserved);
66 if (Attrs.hasFnAttr(Kind: "aarch64_new_za"))
67 Bitmask |= encodeZAState(S: StateValue::New);
68 if (Attrs.hasFnAttr(Kind: "aarch64_in_zt0"))
69 Bitmask |= encodeZT0State(S: StateValue::In);
70 if (Attrs.hasFnAttr(Kind: "aarch64_out_zt0"))
71 Bitmask |= encodeZT0State(S: StateValue::Out);
72 if (Attrs.hasFnAttr(Kind: "aarch64_inout_zt0"))
73 Bitmask |= encodeZT0State(S: StateValue::InOut);
74 if (Attrs.hasFnAttr(Kind: "aarch64_preserves_zt0"))
75 Bitmask |= encodeZT0State(S: StateValue::Preserved);
76 if (Attrs.hasFnAttr(Kind: "aarch64_new_zt0"))
77 Bitmask |= encodeZT0State(S: StateValue::New);
78}
79
80void SMEAttrs::addKnownFunctionAttrs(StringRef FuncName) {
81 unsigned KnownAttrs = SMEAttrs::Normal;
82 if (FuncName == "__arm_tpidr2_save" || FuncName == "__arm_sme_state")
83 KnownAttrs |= (SMEAttrs::SM_Compatible | SMEAttrs::SME_ABI_Routine);
84 if (FuncName == "__arm_tpidr2_restore")
85 KnownAttrs |= SMEAttrs::SM_Compatible | encodeZAState(S: StateValue::In) |
86 SMEAttrs::SME_ABI_Routine;
87 if (FuncName == "__arm_sc_memcpy" || FuncName == "__arm_sc_memset" ||
88 FuncName == "__arm_sc_memmove" || FuncName == "__arm_sc_memchr")
89 KnownAttrs |= SMEAttrs::SM_Compatible;
90 if (FuncName == "__arm_sme_save" || FuncName == "__arm_sme_restore" ||
91 FuncName == "__arm_sme_state_size")
92 KnownAttrs |= SMEAttrs::SM_Compatible | SMEAttrs::SME_ABI_Routine;
93 set(M: KnownAttrs);
94}
95
96bool SMECallAttrs::requiresSMChange() const {
97 if (callee().hasStreamingCompatibleInterface())
98 return false;
99
100 // Both non-streaming
101 if (caller().hasNonStreamingInterfaceAndBody() &&
102 callee().hasNonStreamingInterface())
103 return false;
104
105 // Both streaming
106 if (caller().hasStreamingInterfaceOrBody() &&
107 callee().hasStreamingInterface())
108 return false;
109
110 return true;
111}
112
113SMECallAttrs::SMECallAttrs(const CallBase &CB)
114 : CallerFn(*CB.getFunction()), CalledFn(SMEAttrs::Normal),
115 Callsite(CB.getAttributes()), IsIndirect(CB.isIndirectCall()) {
116 if (auto *CalledFunction = CB.getCalledFunction())
117 CalledFn = SMEAttrs(*CalledFunction, SMEAttrs::InferAttrsFromName::Yes);
118
119 // FIXME: We probably should not allow SME attributes on direct calls but
120 // clang duplicates streaming mode attributes at each callsite.
121 assert((IsIndirect ||
122 ((Callsite.withoutPerCallsiteFlags() | CalledFn) == CalledFn)) &&
123 "SME attributes at callsite do not match declaration");
124}
125