1bdd1243dSDimitry Andric //===-- AArch64SMEAttributes.cpp - Helper for interpreting SME attributes -===// 2bdd1243dSDimitry Andric // 3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6bdd1243dSDimitry Andric // 7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 8bdd1243dSDimitry Andric 9bdd1243dSDimitry Andric #include "AArch64SMEAttributes.h" 10bdd1243dSDimitry Andric #include "llvm/IR/InstrTypes.h" 11bdd1243dSDimitry Andric #include <cassert> 12bdd1243dSDimitry Andric 13bdd1243dSDimitry Andric using namespace llvm; 14bdd1243dSDimitry Andric 15bdd1243dSDimitry Andric void SMEAttrs::set(unsigned M, bool Enable) { 16bdd1243dSDimitry Andric if (Enable) 17bdd1243dSDimitry Andric Bitmask |= M; 18bdd1243dSDimitry Andric else 19bdd1243dSDimitry Andric Bitmask &= ~M; 20bdd1243dSDimitry Andric 21bdd1243dSDimitry Andric assert(!(hasStreamingInterface() && hasStreamingCompatibleInterface()) && 22bdd1243dSDimitry Andric "SM_Enabled and SM_Compatible are mutually exclusive"); 23*5f757f3fSDimitry Andric assert(!(hasNewZABody() && hasSharedZAInterface()) && 24bdd1243dSDimitry Andric "ZA_New and ZA_Shared are mutually exclusive"); 25*5f757f3fSDimitry Andric assert(!(hasNewZABody() && preservesZA()) && 26bdd1243dSDimitry Andric "ZA_New and ZA_Preserved are mutually exclusive"); 27*5f757f3fSDimitry Andric assert(!(hasNewZABody() && (Bitmask & ZA_NoLazySave)) && 28*5f757f3fSDimitry Andric "ZA_New and ZA_NoLazySave are mutually exclusive"); 29*5f757f3fSDimitry Andric assert(!(hasSharedZAInterface() && (Bitmask & ZA_NoLazySave)) && 30*5f757f3fSDimitry Andric "ZA_Shared and ZA_NoLazySave are mutually exclusive"); 31bdd1243dSDimitry Andric } 32bdd1243dSDimitry Andric 33bdd1243dSDimitry Andric SMEAttrs::SMEAttrs(const CallBase &CB) { 34bdd1243dSDimitry Andric *this = SMEAttrs(CB.getAttributes()); 35*5f757f3fSDimitry Andric if (auto *F = CB.getCalledFunction()) { 36*5f757f3fSDimitry Andric set(SMEAttrs(*F).Bitmask | SMEAttrs(F->getName()).Bitmask); 37*5f757f3fSDimitry Andric } 38*5f757f3fSDimitry Andric } 39*5f757f3fSDimitry Andric 40*5f757f3fSDimitry Andric SMEAttrs::SMEAttrs(StringRef FuncName) : Bitmask(0) { 41*5f757f3fSDimitry Andric if (FuncName == "__arm_tpidr2_save" || FuncName == "__arm_sme_state") 42*5f757f3fSDimitry Andric Bitmask |= (SMEAttrs::SM_Compatible | SMEAttrs::ZA_Preserved | 43*5f757f3fSDimitry Andric SMEAttrs::ZA_NoLazySave); 44*5f757f3fSDimitry Andric if (FuncName == "__arm_tpidr2_restore") 45*5f757f3fSDimitry Andric Bitmask |= (SMEAttrs::SM_Compatible | SMEAttrs::ZA_Shared | 46*5f757f3fSDimitry Andric SMEAttrs::ZA_NoLazySave); 47bdd1243dSDimitry Andric } 48bdd1243dSDimitry Andric 49bdd1243dSDimitry Andric SMEAttrs::SMEAttrs(const AttributeList &Attrs) { 50bdd1243dSDimitry Andric Bitmask = 0; 51bdd1243dSDimitry Andric if (Attrs.hasFnAttr("aarch64_pstate_sm_enabled")) 52bdd1243dSDimitry Andric Bitmask |= SM_Enabled; 53bdd1243dSDimitry Andric if (Attrs.hasFnAttr("aarch64_pstate_sm_compatible")) 54bdd1243dSDimitry Andric Bitmask |= SM_Compatible; 55bdd1243dSDimitry Andric if (Attrs.hasFnAttr("aarch64_pstate_sm_body")) 56bdd1243dSDimitry Andric Bitmask |= SM_Body; 57bdd1243dSDimitry Andric if (Attrs.hasFnAttr("aarch64_pstate_za_shared")) 58bdd1243dSDimitry Andric Bitmask |= ZA_Shared; 59bdd1243dSDimitry Andric if (Attrs.hasFnAttr("aarch64_pstate_za_new")) 60bdd1243dSDimitry Andric Bitmask |= ZA_New; 61bdd1243dSDimitry Andric if (Attrs.hasFnAttr("aarch64_pstate_za_preserved")) 62bdd1243dSDimitry Andric Bitmask |= ZA_Preserved; 63bdd1243dSDimitry Andric } 64bdd1243dSDimitry Andric 65bdd1243dSDimitry Andric std::optional<bool> 66bdd1243dSDimitry Andric SMEAttrs::requiresSMChange(const SMEAttrs &Callee, 67bdd1243dSDimitry Andric bool BodyOverridesInterface) const { 68bdd1243dSDimitry Andric // If the transition is not through a call (e.g. when considering inlining) 69bdd1243dSDimitry Andric // and Callee has a streaming body, then we can ignore the interface of 70bdd1243dSDimitry Andric // Callee. 71bdd1243dSDimitry Andric if (BodyOverridesInterface && Callee.hasStreamingBody()) { 72bdd1243dSDimitry Andric return hasStreamingInterfaceOrBody() ? std::nullopt 73bdd1243dSDimitry Andric : std::optional<bool>(true); 74bdd1243dSDimitry Andric } 75bdd1243dSDimitry Andric 76bdd1243dSDimitry Andric if (Callee.hasStreamingCompatibleInterface()) 77bdd1243dSDimitry Andric return std::nullopt; 78bdd1243dSDimitry Andric 79bdd1243dSDimitry Andric // Both non-streaming 80bdd1243dSDimitry Andric if (hasNonStreamingInterfaceAndBody() && Callee.hasNonStreamingInterface()) 81bdd1243dSDimitry Andric return std::nullopt; 82bdd1243dSDimitry Andric 83bdd1243dSDimitry Andric // Both streaming 84bdd1243dSDimitry Andric if (hasStreamingInterfaceOrBody() && Callee.hasStreamingInterface()) 85bdd1243dSDimitry Andric return std::nullopt; 86bdd1243dSDimitry Andric 87bdd1243dSDimitry Andric return Callee.hasStreamingInterface(); 88bdd1243dSDimitry Andric } 89