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