xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AArch64/Utils/AArch64SMEAttributes.cpp (revision 9c77fb6aaa366cbabc80ee1b834bcfe4df135491)
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 
13 using namespace llvm;
14 
15 void 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 
46 SMEAttrs::SMEAttrs(const AttributeList &Attrs) {
47   Bitmask = 0;
48   if (Attrs.hasFnAttr("aarch64_pstate_sm_enabled"))
49     Bitmask |= SM_Enabled;
50   if (Attrs.hasFnAttr("aarch64_pstate_sm_compatible"))
51     Bitmask |= SM_Compatible;
52   if (Attrs.hasFnAttr("aarch64_pstate_sm_body"))
53     Bitmask |= SM_Body;
54   if (Attrs.hasFnAttr("aarch64_za_state_agnostic"))
55     Bitmask |= ZA_State_Agnostic;
56   if (Attrs.hasFnAttr("aarch64_zt0_undef"))
57     Bitmask |= ZT0_Undef;
58   if (Attrs.hasFnAttr("aarch64_in_za"))
59     Bitmask |= encodeZAState(StateValue::In);
60   if (Attrs.hasFnAttr("aarch64_out_za"))
61     Bitmask |= encodeZAState(StateValue::Out);
62   if (Attrs.hasFnAttr("aarch64_inout_za"))
63     Bitmask |= encodeZAState(StateValue::InOut);
64   if (Attrs.hasFnAttr("aarch64_preserves_za"))
65     Bitmask |= encodeZAState(StateValue::Preserved);
66   if (Attrs.hasFnAttr("aarch64_new_za"))
67     Bitmask |= encodeZAState(StateValue::New);
68   if (Attrs.hasFnAttr("aarch64_in_zt0"))
69     Bitmask |= encodeZT0State(StateValue::In);
70   if (Attrs.hasFnAttr("aarch64_out_zt0"))
71     Bitmask |= encodeZT0State(StateValue::Out);
72   if (Attrs.hasFnAttr("aarch64_inout_zt0"))
73     Bitmask |= encodeZT0State(StateValue::InOut);
74   if (Attrs.hasFnAttr("aarch64_preserves_zt0"))
75     Bitmask |= encodeZT0State(StateValue::Preserved);
76   if (Attrs.hasFnAttr("aarch64_new_zt0"))
77     Bitmask |= encodeZT0State(StateValue::New);
78 }
79 
80 void 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(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(KnownAttrs);
94 }
95 
96 bool 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 
113 SMECallAttrs::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