Path: blob/main/contrib/llvm-project/clang/utils/TableGen/SveEmitter.cpp
35230 views
//===- SveEmitter.cpp - Generate arm_sve.h for use with clang -*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This tablegen backend is responsible for emitting arm_sve.h, which includes9// a declaration and definition of each function specified by the ARM C/C++10// Language Extensions (ACLE).11//12// For details, visit:13// https://developer.arm.com/architectures/system-architectures/software-standards/acle14//15// Each SVE instruction is implemented in terms of 1 or more functions which16// are suffixed with the element type of the input vectors. Functions may be17// implemented in terms of generic vector operations such as +, *, -, etc. or18// by calling a __builtin_-prefixed function which will be handled by clang's19// CodeGen library.20//21// See also the documentation in include/clang/Basic/arm_sve.td.22//23//===----------------------------------------------------------------------===//2425#include "llvm/ADT/ArrayRef.h"26#include "llvm/ADT/STLExtras.h"27#include "llvm/ADT/StringExtras.h"28#include "llvm/ADT/StringMap.h"29#include "llvm/TableGen/Error.h"30#include "llvm/TableGen/Record.h"31#include <array>32#include <cctype>33#include <set>34#include <sstream>35#include <string>36#include <tuple>3738using namespace llvm;3940enum ClassKind {41ClassNone,42ClassS, // signed/unsigned, e.g., "_s8", "_u8" suffix43ClassG, // Overloaded name without type suffix44};4546enum class ACLEKind { SVE, SME };4748using TypeSpec = std::string;4950namespace {5152class ImmCheck {53unsigned Arg;54unsigned Kind;55unsigned ElementSizeInBits;5657public:58ImmCheck(unsigned Arg, unsigned Kind, unsigned ElementSizeInBits = 0)59: Arg(Arg), Kind(Kind), ElementSizeInBits(ElementSizeInBits) {}60ImmCheck(const ImmCheck &Other) = default;61~ImmCheck() = default;6263unsigned getArg() const { return Arg; }64unsigned getKind() const { return Kind; }65unsigned getElementSizeInBits() const { return ElementSizeInBits; }66};6768class SVEType {69bool Float, Signed, Immediate, Void, Constant, Pointer, BFloat;70bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp,71Svcount;72unsigned Bitwidth, ElementBitwidth, NumVectors;7374public:75SVEType() : SVEType("", 'v') {}7677SVEType(StringRef TS, char CharMod, unsigned NumVectors = 1)78: Float(false), Signed(true), Immediate(false), Void(false),79Constant(false), Pointer(false), BFloat(false), DefaultType(false),80IsScalable(true), Predicate(false), PredicatePattern(false),81PrefetchOp(false), Svcount(false), Bitwidth(128), ElementBitwidth(~0U),82NumVectors(NumVectors) {83if (!TS.empty())84applyTypespec(TS);85applyModifier(CharMod);86}8788SVEType(const SVEType &Base, unsigned NumV) : SVEType(Base) {89NumVectors = NumV;90}9192bool isPointer() const { return Pointer; }93bool isVoidPointer() const { return Pointer && Void; }94bool isSigned() const { return Signed; }95bool isImmediate() const { return Immediate; }96bool isScalar() const { return NumVectors == 0; }97bool isVector() const { return NumVectors > 0; }98bool isScalableVector() const { return isVector() && IsScalable; }99bool isFixedLengthVector() const { return isVector() && !IsScalable; }100bool isChar() const { return ElementBitwidth == 8; }101bool isVoid() const { return Void && !Pointer; }102bool isDefault() const { return DefaultType; }103bool isFloat() const { return Float && !BFloat; }104bool isBFloat() const { return BFloat && !Float; }105bool isFloatingPoint() const { return Float || BFloat; }106bool isInteger() const {107return !isFloatingPoint() && !Predicate && !Svcount;108}109bool isScalarPredicate() const {110return !isFloatingPoint() && Predicate && NumVectors == 0;111}112bool isPredicateVector() const { return Predicate; }113bool isPredicatePattern() const { return PredicatePattern; }114bool isPrefetchOp() const { return PrefetchOp; }115bool isSvcount() const { return Svcount; }116bool isConstant() const { return Constant; }117unsigned getElementSizeInBits() const { return ElementBitwidth; }118unsigned getNumVectors() const { return NumVectors; }119120unsigned getNumElements() const {121assert(ElementBitwidth != ~0U);122return Bitwidth / ElementBitwidth;123}124unsigned getSizeInBits() const {125return Bitwidth;126}127128/// Return the string representation of a type, which is an encoded129/// string for passing to the BUILTIN() macro in Builtins.def.130std::string builtin_str() const;131132/// Return the C/C++ string representation of a type for use in the133/// arm_sve.h header file.134std::string str() const;135136private:137/// Creates the type based on the typespec string in TS.138void applyTypespec(StringRef TS);139140/// Applies a prototype modifier to the type.141void applyModifier(char Mod);142};143144class SVEEmitter;145146/// The main grunt class. This represents an instantiation of an intrinsic with147/// a particular typespec and prototype.148class Intrinsic {149/// The unmangled name.150std::string Name;151152/// The name of the corresponding LLVM IR intrinsic.153std::string LLVMName;154155/// Intrinsic prototype.156std::string Proto;157158/// The base type spec for this intrinsic.159TypeSpec BaseTypeSpec;160161/// The base class kind. Most intrinsics use ClassS, which has full type162/// info for integers (_s32/_u32), or ClassG which is used for overloaded163/// intrinsics.164ClassKind Class;165166/// The architectural #ifdef guard.167std::string SVEGuard, SMEGuard;168169// The merge suffix such as _m, _x or _z.170std::string MergeSuffix;171172/// The types of return value [0] and parameters [1..].173std::vector<SVEType> Types;174175/// The "base type", which is VarType('d', BaseTypeSpec).176SVEType BaseType;177178uint64_t Flags;179180SmallVector<ImmCheck, 2> ImmChecks;181182public:183Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,184StringRef MergeSuffix, uint64_t MemoryElementTy, StringRef LLVMName,185uint64_t Flags, ArrayRef<ImmCheck> ImmChecks, TypeSpec BT,186ClassKind Class, SVEEmitter &Emitter, StringRef SVEGuard,187StringRef SMEGuard);188189~Intrinsic()=default;190191std::string getName() const { return Name; }192std::string getLLVMName() const { return LLVMName; }193std::string getProto() const { return Proto; }194TypeSpec getBaseTypeSpec() const { return BaseTypeSpec; }195SVEType getBaseType() const { return BaseType; }196197StringRef getSVEGuard() const { return SVEGuard; }198StringRef getSMEGuard() const { return SMEGuard; }199void printGuard(raw_ostream &OS) const {200if (!SVEGuard.empty() && SMEGuard.empty())201OS << SVEGuard;202else if (SVEGuard.empty() && !SMEGuard.empty())203OS << SMEGuard;204else {205if (SVEGuard.find(",") != std::string::npos ||206SVEGuard.find("|") != std::string::npos)207OS << "(" << SVEGuard << ")";208else209OS << SVEGuard;210OS << "|";211if (SMEGuard.find(",") != std::string::npos ||212SMEGuard.find("|") != std::string::npos)213OS << "(" << SMEGuard << ")";214else215OS << SMEGuard;216}217}218ClassKind getClassKind() const { return Class; }219220SVEType getReturnType() const { return Types[0]; }221ArrayRef<SVEType> getTypes() const { return Types; }222SVEType getParamType(unsigned I) const { return Types[I + 1]; }223unsigned getNumParams() const {224return Proto.size() - (2 * llvm::count(Proto, '.')) - 1;225}226227uint64_t getFlags() const { return Flags; }228bool isFlagSet(uint64_t Flag) const { return Flags & Flag;}229230ArrayRef<ImmCheck> getImmChecks() const { return ImmChecks; }231232/// Return the type string for a BUILTIN() macro in Builtins.def.233std::string getBuiltinTypeStr();234235/// Return the name, mangled with type information. The name is mangled for236/// ClassS, so will add type suffixes such as _u32/_s32.237std::string getMangledName() const { return mangleName(ClassS); }238239/// As above, but mangles the LLVM name instead.240std::string getMangledLLVMName() const { return mangleLLVMName(); }241242/// Returns true if the intrinsic is overloaded, in that it should also generate243/// a short form without the type-specifiers, e.g. 'svld1(..)' instead of244/// 'svld1_u32(..)'.245static bool isOverloadedIntrinsic(StringRef Name) {246auto BrOpen = Name.find('[');247auto BrClose = Name.find(']');248return BrOpen != std::string::npos && BrClose != std::string::npos;249}250251/// Return true if the intrinsic takes a splat operand.252bool hasSplat() const {253// These prototype modifiers are described in arm_sve.td.254return Proto.find_first_of("ajfrKLR@") != std::string::npos;255}256257/// Return the parameter index of the splat operand.258unsigned getSplatIdx() const {259unsigned I = 1, Param = 0;260for (; I < Proto.size(); ++I, ++Param) {261if (Proto[I] == 'a' || Proto[I] == 'j' || Proto[I] == 'f' ||262Proto[I] == 'r' || Proto[I] == 'K' || Proto[I] == 'L' ||263Proto[I] == 'R' || Proto[I] == '@')264break;265266// Multivector modifier can be skipped267if (Proto[I] == '.')268I += 2;269}270assert(I != Proto.size() && "Prototype has no splat operand");271return Param;272}273274/// Emits the intrinsic declaration to the ostream.275void emitIntrinsic(raw_ostream &OS, SVEEmitter &Emitter, ACLEKind Kind) const;276277private:278std::string getMergeSuffix() const { return MergeSuffix; }279std::string mangleName(ClassKind LocalCK) const;280std::string mangleLLVMName() const;281std::string replaceTemplatedArgs(std::string Name, TypeSpec TS,282std::string Proto) const;283};284285class SVEEmitter {286private:287// The reinterpret builtins are generated separately because they288// need the cross product of all types (121 functions in total),289// which is inconvenient to specify in the arm_sve.td file or290// generate in CGBuiltin.cpp.291struct ReinterpretTypeInfo {292SVEType BaseType;293const char *Suffix;294};295296static const std::array<ReinterpretTypeInfo, 12> Reinterprets;297298RecordKeeper &Records;299llvm::StringMap<uint64_t> EltTypes;300llvm::StringMap<uint64_t> MemEltTypes;301llvm::StringMap<uint64_t> FlagTypes;302llvm::StringMap<uint64_t> MergeTypes;303llvm::StringMap<uint64_t> ImmCheckTypes;304305public:306SVEEmitter(RecordKeeper &R) : Records(R) {307for (auto *RV : Records.getAllDerivedDefinitions("EltType"))308EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");309for (auto *RV : Records.getAllDerivedDefinitions("MemEltType"))310MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");311for (auto *RV : Records.getAllDerivedDefinitions("FlagType"))312FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");313for (auto *RV : Records.getAllDerivedDefinitions("MergeType"))314MergeTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");315for (auto *RV : Records.getAllDerivedDefinitions("ImmCheckType"))316ImmCheckTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");317}318319/// Returns the enum value for the immcheck type320unsigned getEnumValueForImmCheck(StringRef C) const {321auto It = ImmCheckTypes.find(C);322if (It != ImmCheckTypes.end())323return It->getValue();324llvm_unreachable("Unsupported imm check");325}326327/// Returns the enum value for the flag type328uint64_t getEnumValueForFlag(StringRef C) const {329auto Res = FlagTypes.find(C);330if (Res != FlagTypes.end())331return Res->getValue();332llvm_unreachable("Unsupported flag");333}334335// Returns the SVETypeFlags for a given value and mask.336uint64_t encodeFlag(uint64_t V, StringRef MaskName) const {337auto It = FlagTypes.find(MaskName);338if (It != FlagTypes.end()) {339uint64_t Mask = It->getValue();340unsigned Shift = llvm::countr_zero(Mask);341assert(Shift < 64 && "Mask value produced an invalid shift value");342return (V << Shift) & Mask;343}344llvm_unreachable("Unsupported flag");345}346347// Returns the SVETypeFlags for the given element type.348uint64_t encodeEltType(StringRef EltName) {349auto It = EltTypes.find(EltName);350if (It != EltTypes.end())351return encodeFlag(It->getValue(), "EltTypeMask");352llvm_unreachable("Unsupported EltType");353}354355// Returns the SVETypeFlags for the given memory element type.356uint64_t encodeMemoryElementType(uint64_t MT) {357return encodeFlag(MT, "MemEltTypeMask");358}359360// Returns the SVETypeFlags for the given merge type.361uint64_t encodeMergeType(uint64_t MT) {362return encodeFlag(MT, "MergeTypeMask");363}364365// Returns the SVETypeFlags for the given splat operand.366unsigned encodeSplatOperand(unsigned SplatIdx) {367assert(SplatIdx < 7 && "SplatIdx out of encodable range");368return encodeFlag(SplatIdx + 1, "SplatOperandMask");369}370371// Returns the SVETypeFlags value for the given SVEType.372uint64_t encodeTypeFlags(const SVEType &T);373374/// Emit arm_sve.h.375void createHeader(raw_ostream &o);376377// Emits core intrinsics in both arm_sme.h and arm_sve.h378void createCoreHeaderIntrinsics(raw_ostream &o, SVEEmitter &Emitter,379ACLEKind Kind);380381/// Emit all the __builtin prototypes and code needed by Sema.382void createBuiltins(raw_ostream &o);383384/// Emit all the information needed to map builtin -> LLVM IR intrinsic.385void createCodeGenMap(raw_ostream &o);386387/// Emit all the range checks for the immediates.388void createRangeChecks(raw_ostream &o);389390/// Create the SVETypeFlags used in CGBuiltins391void createTypeFlags(raw_ostream &o);392393/// Emit arm_sme.h.394void createSMEHeader(raw_ostream &o);395396/// Emit all the SME __builtin prototypes and code needed by Sema.397void createSMEBuiltins(raw_ostream &o);398399/// Emit all the information needed to map builtin -> LLVM IR intrinsic.400void createSMECodeGenMap(raw_ostream &o);401402/// Create a table for a builtin's requirement for PSTATE.SM.403void createStreamingAttrs(raw_ostream &o, ACLEKind Kind);404405/// Emit all the range checks for the immediates.406void createSMERangeChecks(raw_ostream &o);407408/// Create a table for a builtin's requirement for PSTATE.ZA.409void createBuiltinZAState(raw_ostream &OS);410411/// Create intrinsic and add it to \p Out412void createIntrinsic(Record *R,413SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out);414};415416const std::array<SVEEmitter::ReinterpretTypeInfo, 12> SVEEmitter::Reinterprets =417{{{SVEType("c", 'd'), "s8"},418{SVEType("Uc", 'd'), "u8"},419{SVEType("s", 'd'), "s16"},420{SVEType("Us", 'd'), "u16"},421{SVEType("i", 'd'), "s32"},422{SVEType("Ui", 'd'), "u32"},423{SVEType("l", 'd'), "s64"},424{SVEType("Ul", 'd'), "u64"},425{SVEType("h", 'd'), "f16"},426{SVEType("b", 'd'), "bf16"},427{SVEType("f", 'd'), "f32"},428{SVEType("d", 'd'), "f64"}}};429430} // end anonymous namespace431432433//===----------------------------------------------------------------------===//434// Type implementation435//===----------------------------------------------------------------------===//436437std::string SVEType::builtin_str() const {438std::string S;439if (isVoid())440return "v";441442if (isScalarPredicate())443return "b";444445if (isSvcount())446return "Qa";447448if (isVoidPointer())449S += "v";450else if (!isFloatingPoint())451switch (ElementBitwidth) {452case 1: S += "b"; break;453case 8: S += "c"; break;454case 16: S += "s"; break;455case 32: S += "i"; break;456case 64: S += "Wi"; break;457case 128: S += "LLLi"; break;458default: llvm_unreachable("Unhandled case!");459}460else if (isFloat())461switch (ElementBitwidth) {462case 16: S += "h"; break;463case 32: S += "f"; break;464case 64: S += "d"; break;465default: llvm_unreachable("Unhandled case!");466}467else if (isBFloat()) {468assert(ElementBitwidth == 16 && "Not a valid BFloat.");469S += "y";470}471472if (!isFloatingPoint()) {473if ((isChar() || isPointer()) && !isVoidPointer()) {474// Make chars and typed pointers explicitly signed.475if (Signed)476S = "S" + S;477else if (!Signed)478S = "U" + S;479} else if (!isVoidPointer() && !Signed) {480S = "U" + S;481}482}483484// Constant indices are "int", but have the "constant expression" modifier.485if (isImmediate()) {486assert(!isFloat() && "fp immediates are not supported");487S = "I" + S;488}489490if (isScalar()) {491if (Constant) S += "C";492if (Pointer) S += "*";493return S;494}495496if (isFixedLengthVector())497return "V" + utostr(getNumElements() * NumVectors) + S;498return "q" + utostr(getNumElements() * NumVectors) + S;499}500501std::string SVEType::str() const {502if (isPredicatePattern())503return "enum svpattern";504505if (isPrefetchOp())506return "enum svprfop";507508std::string S;509if (Void)510S += "void";511else {512if (isScalableVector() || isSvcount())513S += "sv";514if (!Signed && !isFloatingPoint())515S += "u";516517if (Float)518S += "float";519else if (isSvcount())520S += "count";521else if (isScalarPredicate() || isPredicateVector())522S += "bool";523else if (isBFloat())524S += "bfloat";525else526S += "int";527528if (!isScalarPredicate() && !isPredicateVector() && !isSvcount())529S += utostr(ElementBitwidth);530if (isFixedLengthVector())531S += "x" + utostr(getNumElements());532if (NumVectors > 1)533S += "x" + utostr(NumVectors);534if (!isScalarPredicate())535S += "_t";536}537538if (Constant)539S += " const";540if (Pointer)541S += " *";542543return S;544}545546void SVEType::applyTypespec(StringRef TS) {547for (char I : TS) {548switch (I) {549case 'Q':550Svcount = true;551break;552case 'P':553Predicate = true;554break;555case 'U':556Signed = false;557break;558case 'c':559ElementBitwidth = 8;560break;561case 's':562ElementBitwidth = 16;563break;564case 'i':565ElementBitwidth = 32;566break;567case 'l':568ElementBitwidth = 64;569break;570case 'q':571ElementBitwidth = 128;572break;573case 'h':574Float = true;575ElementBitwidth = 16;576break;577case 'f':578Float = true;579ElementBitwidth = 32;580break;581case 'd':582Float = true;583ElementBitwidth = 64;584break;585case 'b':586BFloat = true;587Float = false;588ElementBitwidth = 16;589break;590default:591llvm_unreachable("Unhandled type code!");592}593}594assert(ElementBitwidth != ~0U && "Bad element bitwidth!");595}596597void SVEType::applyModifier(char Mod) {598switch (Mod) {599case 'v':600Void = true;601break;602case 'd':603DefaultType = true;604break;605case 'c':606Constant = true;607[[fallthrough]];608case 'p':609Pointer = true;610Bitwidth = ElementBitwidth;611NumVectors = 0;612break;613case 'e':614Signed = false;615ElementBitwidth /= 2;616break;617case 'h':618ElementBitwidth /= 2;619break;620case 'q':621ElementBitwidth /= 4;622break;623case 'b':624Signed = false;625Float = false;626BFloat = false;627ElementBitwidth /= 4;628break;629case 'o':630ElementBitwidth *= 4;631break;632case 'P':633Signed = true;634Float = false;635BFloat = false;636Predicate = true;637Svcount = false;638Bitwidth = 16;639ElementBitwidth = 1;640break;641case '{':642IsScalable = false;643Bitwidth = 128;644NumVectors = 1;645break;646case 's':647case 'a':648Bitwidth = ElementBitwidth;649NumVectors = 0;650break;651case 'R':652ElementBitwidth /= 2;653NumVectors = 0;654break;655case 'r':656ElementBitwidth /= 4;657NumVectors = 0;658break;659case '@':660Signed = false;661Float = false;662BFloat = false;663ElementBitwidth /= 4;664NumVectors = 0;665break;666case 'K':667Signed = true;668Float = false;669BFloat = false;670Bitwidth = ElementBitwidth;671NumVectors = 0;672break;673case 'L':674Signed = false;675Float = false;676BFloat = false;677Bitwidth = ElementBitwidth;678NumVectors = 0;679break;680case 'u':681Predicate = false;682Svcount = false;683Signed = false;684Float = false;685BFloat = false;686break;687case 'x':688Predicate = false;689Svcount = false;690Signed = true;691Float = false;692BFloat = false;693break;694case 'i':695Predicate = false;696Svcount = false;697Float = false;698BFloat = false;699ElementBitwidth = Bitwidth = 64;700NumVectors = 0;701Signed = false;702Immediate = true;703break;704case 'I':705Predicate = false;706Svcount = false;707Float = false;708BFloat = false;709ElementBitwidth = Bitwidth = 32;710NumVectors = 0;711Signed = true;712Immediate = true;713PredicatePattern = true;714break;715case 'J':716Predicate = false;717Svcount = false;718Float = false;719BFloat = false;720ElementBitwidth = Bitwidth = 32;721NumVectors = 0;722Signed = true;723Immediate = true;724PrefetchOp = true;725break;726case 'k':727Predicate = false;728Svcount = false;729Signed = true;730Float = false;731BFloat = false;732ElementBitwidth = Bitwidth = 32;733NumVectors = 0;734break;735case 'l':736Predicate = false;737Svcount = false;738Signed = true;739Float = false;740BFloat = false;741ElementBitwidth = Bitwidth = 64;742NumVectors = 0;743break;744case 'm':745Predicate = false;746Svcount = false;747Signed = false;748Float = false;749BFloat = false;750ElementBitwidth = Bitwidth = 32;751NumVectors = 0;752break;753case 'n':754Predicate = false;755Svcount = false;756Signed = false;757Float = false;758BFloat = false;759ElementBitwidth = Bitwidth = 64;760NumVectors = 0;761break;762case 'w':763ElementBitwidth = 64;764break;765case 'j':766ElementBitwidth = Bitwidth = 64;767NumVectors = 0;768break;769case 'f':770Signed = false;771ElementBitwidth = Bitwidth = 64;772NumVectors = 0;773break;774case 'g':775Signed = false;776Float = false;777BFloat = false;778ElementBitwidth = 64;779break;780case '[':781Signed = false;782Float = false;783BFloat = false;784ElementBitwidth = 8;785break;786case 't':787Signed = true;788Float = false;789BFloat = false;790ElementBitwidth = 32;791break;792case 'z':793Signed = false;794Float = false;795BFloat = false;796ElementBitwidth = 32;797break;798case 'O':799Predicate = false;800Svcount = false;801Float = true;802ElementBitwidth = 16;803break;804case 'M':805Predicate = false;806Svcount = false;807Float = true;808BFloat = false;809ElementBitwidth = 32;810break;811case 'N':812Predicate = false;813Svcount = false;814Float = true;815ElementBitwidth = 64;816break;817case 'Q':818Constant = true;819Pointer = true;820Void = true;821NumVectors = 0;822break;823case 'S':824Constant = true;825Pointer = true;826ElementBitwidth = Bitwidth = 8;827NumVectors = 0;828Signed = true;829break;830case 'W':831Constant = true;832Pointer = true;833ElementBitwidth = Bitwidth = 8;834NumVectors = 0;835Signed = false;836break;837case 'T':838Constant = true;839Pointer = true;840ElementBitwidth = Bitwidth = 16;841NumVectors = 0;842Signed = true;843break;844case 'X':845Constant = true;846Pointer = true;847ElementBitwidth = Bitwidth = 16;848NumVectors = 0;849Signed = false;850break;851case 'Y':852Constant = true;853Pointer = true;854ElementBitwidth = Bitwidth = 32;855NumVectors = 0;856Signed = false;857break;858case 'U':859Constant = true;860Pointer = true;861ElementBitwidth = Bitwidth = 32;862NumVectors = 0;863Signed = true;864break;865case '%':866Pointer = true;867Void = true;868NumVectors = 0;869break;870case 'A':871Pointer = true;872ElementBitwidth = Bitwidth = 8;873NumVectors = 0;874Signed = true;875break;876case 'B':877Pointer = true;878ElementBitwidth = Bitwidth = 16;879NumVectors = 0;880Signed = true;881break;882case 'C':883Pointer = true;884ElementBitwidth = Bitwidth = 32;885NumVectors = 0;886Signed = true;887break;888case 'D':889Pointer = true;890ElementBitwidth = Bitwidth = 64;891NumVectors = 0;892Signed = true;893break;894case 'E':895Pointer = true;896ElementBitwidth = Bitwidth = 8;897NumVectors = 0;898Signed = false;899break;900case 'F':901Pointer = true;902ElementBitwidth = Bitwidth = 16;903NumVectors = 0;904Signed = false;905break;906case 'G':907Pointer = true;908ElementBitwidth = Bitwidth = 32;909NumVectors = 0;910Signed = false;911break;912case '$':913Predicate = false;914Svcount = false;915Float = false;916BFloat = true;917ElementBitwidth = 16;918break;919case '}':920Predicate = false;921Signed = true;922Svcount = true;923NumVectors = 0;924Float = false;925BFloat = false;926break;927case '.':928llvm_unreachable(". is never a type in itself");929break;930default:931llvm_unreachable("Unhandled character!");932}933}934935/// Returns the modifier and number of vectors for the given operand \p Op.936std::pair<char, unsigned> getProtoModifier(StringRef Proto, unsigned Op) {937for (unsigned P = 0; !Proto.empty(); ++P) {938unsigned NumVectors = 1;939unsigned CharsToSkip = 1;940char Mod = Proto[0];941if (Mod == '2' || Mod == '3' || Mod == '4') {942NumVectors = Mod - '0';943Mod = 'd';944if (Proto.size() > 1 && Proto[1] == '.') {945Mod = Proto[2];946CharsToSkip = 3;947}948}949950if (P == Op)951return {Mod, NumVectors};952953Proto = Proto.drop_front(CharsToSkip);954}955llvm_unreachable("Unexpected Op");956}957958//===----------------------------------------------------------------------===//959// Intrinsic implementation960//===----------------------------------------------------------------------===//961962Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,963StringRef MergeSuffix, uint64_t MemoryElementTy,964StringRef LLVMName, uint64_t Flags,965ArrayRef<ImmCheck> Checks, TypeSpec BT, ClassKind Class,966SVEEmitter &Emitter, StringRef SVEGuard,967StringRef SMEGuard)968: Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()),969BaseTypeSpec(BT), Class(Class), SVEGuard(SVEGuard.str()),970SMEGuard(SMEGuard.str()), MergeSuffix(MergeSuffix.str()),971BaseType(BT, 'd'), Flags(Flags), ImmChecks(Checks.begin(), Checks.end()) {972// Types[0] is the return value.973for (unsigned I = 0; I < (getNumParams() + 1); ++I) {974char Mod;975unsigned NumVectors;976std::tie(Mod, NumVectors) = getProtoModifier(Proto, I);977SVEType T(BaseTypeSpec, Mod, NumVectors);978Types.push_back(T);979980// Add range checks for immediates981if (I > 0) {982if (T.isPredicatePattern())983ImmChecks.emplace_back(984I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_31"));985else if (T.isPrefetchOp())986ImmChecks.emplace_back(987I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_13"));988}989}990991// Set flags based on properties992this->Flags |= Emitter.encodeTypeFlags(BaseType);993this->Flags |= Emitter.encodeMemoryElementType(MemoryElementTy);994this->Flags |= Emitter.encodeMergeType(MergeTy);995if (hasSplat())996this->Flags |= Emitter.encodeSplatOperand(getSplatIdx());997}998999std::string Intrinsic::getBuiltinTypeStr() {1000std::string S = getReturnType().builtin_str();1001for (unsigned I = 0; I < getNumParams(); ++I)1002S += getParamType(I).builtin_str();10031004return S;1005}10061007std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS,1008std::string Proto) const {1009std::string Ret = Name;1010while (Ret.find('{') != std::string::npos) {1011size_t Pos = Ret.find('{');1012size_t End = Ret.find('}');1013unsigned NumChars = End - Pos + 1;1014assert(NumChars == 3 && "Unexpected template argument");10151016SVEType T;1017char C = Ret[Pos+1];1018switch(C) {1019default:1020llvm_unreachable("Unknown predication specifier");1021case 'd':1022T = SVEType(TS, 'd');1023break;1024case '0':1025case '1':1026case '2':1027case '3':1028T = SVEType(TS, Proto[C - '0']);1029break;1030}10311032// Replace templated arg with the right suffix (e.g. u32)1033std::string TypeCode;1034if (T.isInteger())1035TypeCode = T.isSigned() ? 's' : 'u';1036else if (T.isSvcount())1037TypeCode = 'c';1038else if (T.isPredicateVector())1039TypeCode = 'b';1040else if (T.isBFloat())1041TypeCode = "bf";1042else1043TypeCode = 'f';1044Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits()));1045}10461047return Ret;1048}10491050std::string Intrinsic::mangleLLVMName() const {1051std::string S = getLLVMName();10521053// Replace all {d} like expressions with e.g. 'u32'1054return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto());1055}10561057std::string Intrinsic::mangleName(ClassKind LocalCK) const {1058std::string S = getName();10591060if (LocalCK == ClassG) {1061// Remove the square brackets and everything in between.1062while (S.find('[') != std::string::npos) {1063auto Start = S.find('[');1064auto End = S.find(']');1065S.erase(Start, (End-Start)+1);1066}1067} else {1068// Remove the square brackets.1069while (S.find('[') != std::string::npos) {1070auto BrPos = S.find('[');1071if (BrPos != std::string::npos)1072S.erase(BrPos, 1);1073BrPos = S.find(']');1074if (BrPos != std::string::npos)1075S.erase(BrPos, 1);1076}1077}10781079// Replace all {d} like expressions with e.g. 'u32'1080return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) +1081getMergeSuffix();1082}10831084void Intrinsic::emitIntrinsic(raw_ostream &OS, SVEEmitter &Emitter,1085ACLEKind Kind) const {1086bool IsOverloaded = getClassKind() == ClassG && getProto().size() > 1;10871088std::string FullName = mangleName(ClassS);1089std::string ProtoName = mangleName(getClassKind());1090OS << (IsOverloaded ? "__aio " : "__ai ")1091<< "__attribute__((__clang_arm_builtin_alias(";10921093switch (Kind) {1094case ACLEKind::SME:1095OS << "__builtin_sme_" << FullName << ")";1096break;1097case ACLEKind::SVE:1098OS << "__builtin_sve_" << FullName << ")";1099break;1100}11011102OS << "))\n";11031104OS << getTypes()[0].str() << " " << ProtoName << "(";1105for (unsigned I = 0; I < getTypes().size() - 1; ++I) {1106if (I != 0)1107OS << ", ";1108OS << getTypes()[I + 1].str();1109}1110OS << ");\n";1111}11121113//===----------------------------------------------------------------------===//1114// SVEEmitter implementation1115//===----------------------------------------------------------------------===//1116uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) {1117if (T.isFloat()) {1118switch (T.getElementSizeInBits()) {1119case 16:1120return encodeEltType("EltTyFloat16");1121case 32:1122return encodeEltType("EltTyFloat32");1123case 64:1124return encodeEltType("EltTyFloat64");1125default:1126llvm_unreachable("Unhandled float element bitwidth!");1127}1128}11291130if (T.isBFloat()) {1131assert(T.getElementSizeInBits() == 16 && "Not a valid BFloat.");1132return encodeEltType("EltTyBFloat16");1133}11341135if (T.isPredicateVector() || T.isSvcount()) {1136switch (T.getElementSizeInBits()) {1137case 8:1138return encodeEltType("EltTyBool8");1139case 16:1140return encodeEltType("EltTyBool16");1141case 32:1142return encodeEltType("EltTyBool32");1143case 64:1144return encodeEltType("EltTyBool64");1145default:1146llvm_unreachable("Unhandled predicate element bitwidth!");1147}1148}11491150switch (T.getElementSizeInBits()) {1151case 8:1152return encodeEltType("EltTyInt8");1153case 16:1154return encodeEltType("EltTyInt16");1155case 32:1156return encodeEltType("EltTyInt32");1157case 64:1158return encodeEltType("EltTyInt64");1159case 128:1160return encodeEltType("EltTyInt128");1161default:1162llvm_unreachable("Unhandled integer element bitwidth!");1163}1164}11651166void SVEEmitter::createIntrinsic(1167Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) {1168StringRef Name = R->getValueAsString("Name");1169StringRef Proto = R->getValueAsString("Prototype");1170StringRef Types = R->getValueAsString("Types");1171StringRef SVEGuard = R->getValueAsString("SVETargetGuard");1172StringRef SMEGuard = R->getValueAsString("SMETargetGuard");1173StringRef LLVMName = R->getValueAsString("LLVMIntrinsic");1174uint64_t Merge = R->getValueAsInt("Merge");1175StringRef MergeSuffix = R->getValueAsString("MergeSuffix");1176uint64_t MemEltType = R->getValueAsInt("MemEltType");1177std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags");1178std::vector<Record*> ImmCheckList = R->getValueAsListOfDefs("ImmChecks");11791180int64_t Flags = 0;1181for (auto FlagRec : FlagsList)1182Flags |= FlagRec->getValueAsInt("Value");11831184// Create a dummy TypeSpec for non-overloaded builtins.1185if (Types.empty()) {1186assert((Flags & getEnumValueForFlag("IsOverloadNone")) &&1187"Expect TypeSpec for overloaded builtin!");1188Types = "i";1189}11901191// Extract type specs from string1192SmallVector<TypeSpec, 8> TypeSpecs;1193TypeSpec Acc;1194for (char I : Types) {1195Acc.push_back(I);1196if (islower(I)) {1197TypeSpecs.push_back(TypeSpec(Acc));1198Acc.clear();1199}1200}12011202// Remove duplicate type specs.1203llvm::sort(TypeSpecs);1204TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()),1205TypeSpecs.end());12061207// Create an Intrinsic for each type spec.1208for (auto TS : TypeSpecs) {1209// Collate a list of range/option checks for the immediates.1210SmallVector<ImmCheck, 2> ImmChecks;1211for (auto *R : ImmCheckList) {1212int64_t Arg = R->getValueAsInt("Arg");1213int64_t EltSizeArg = R->getValueAsInt("EltSizeArg");1214int64_t Kind = R->getValueAsDef("Kind")->getValueAsInt("Value");1215assert(Arg >= 0 && Kind >= 0 && "Arg and Kind must be nonnegative");12161217unsigned ElementSizeInBits = 0;1218char Mod;1219unsigned NumVectors;1220std::tie(Mod, NumVectors) = getProtoModifier(Proto, EltSizeArg + 1);1221if (EltSizeArg >= 0)1222ElementSizeInBits = SVEType(TS, Mod, NumVectors).getElementSizeInBits();1223ImmChecks.push_back(ImmCheck(Arg, Kind, ElementSizeInBits));1224}12251226Out.push_back(std::make_unique<Intrinsic>(1227Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, ImmChecks,1228TS, ClassS, *this, SVEGuard, SMEGuard));12291230// Also generate the short-form (e.g. svadd_m) for the given type-spec.1231if (Intrinsic::isOverloadedIntrinsic(Name))1232Out.push_back(std::make_unique<Intrinsic>(1233Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags,1234ImmChecks, TS, ClassG, *this, SVEGuard, SMEGuard));1235}1236}12371238void SVEEmitter::createCoreHeaderIntrinsics(raw_ostream &OS,1239SVEEmitter &Emitter,1240ACLEKind Kind) {1241SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;1242std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");1243for (auto *R : RV)1244createIntrinsic(R, Defs);12451246// Sort intrinsics in header file by following order/priority:1247// - Architectural guard (i.e. does it require SVE2 or SVE2_AES)1248// - Class (is intrinsic overloaded or not)1249// - Intrinsic name1250std::stable_sort(Defs.begin(), Defs.end(),1251[](const std::unique_ptr<Intrinsic> &A,1252const std::unique_ptr<Intrinsic> &B) {1253auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) {1254return std::make_tuple(1255I->getSVEGuard().str() + I->getSMEGuard().str(),1256(unsigned)I->getClassKind(), I->getName());1257};1258return ToTuple(A) < ToTuple(B);1259});12601261// Actually emit the intrinsic declarations.1262for (auto &I : Defs)1263I->emitIntrinsic(OS, Emitter, Kind);1264}12651266void SVEEmitter::createHeader(raw_ostream &OS) {1267OS << "/*===---- arm_sve.h - ARM SVE intrinsics "1268"-----------------------------------===\n"1269" *\n"1270" *\n"1271" * Part of the LLVM Project, under the Apache License v2.0 with LLVM "1272"Exceptions.\n"1273" * See https://llvm.org/LICENSE.txt for license information.\n"1274" * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"1275" *\n"1276" *===-----------------------------------------------------------------"1277"------===\n"1278" */\n\n";12791280OS << "#ifndef __ARM_SVE_H\n";1281OS << "#define __ARM_SVE_H\n\n";12821283OS << "#if !defined(__LITTLE_ENDIAN__)\n";1284OS << "#error \"Big endian is currently not supported for arm_sve.h\"\n";1285OS << "#endif\n";12861287OS << "#include <stdint.h>\n\n";1288OS << "#ifdef __cplusplus\n";1289OS << "extern \"C\" {\n";1290OS << "#else\n";1291OS << "#include <stdbool.h>\n";1292OS << "#endif\n\n";12931294OS << "typedef __fp16 float16_t;\n";1295OS << "typedef float float32_t;\n";1296OS << "typedef double float64_t;\n";12971298OS << "typedef __SVInt8_t svint8_t;\n";1299OS << "typedef __SVInt16_t svint16_t;\n";1300OS << "typedef __SVInt32_t svint32_t;\n";1301OS << "typedef __SVInt64_t svint64_t;\n";1302OS << "typedef __SVUint8_t svuint8_t;\n";1303OS << "typedef __SVUint16_t svuint16_t;\n";1304OS << "typedef __SVUint32_t svuint32_t;\n";1305OS << "typedef __SVUint64_t svuint64_t;\n";1306OS << "typedef __SVFloat16_t svfloat16_t;\n\n";13071308OS << "typedef __SVBfloat16_t svbfloat16_t;\n";13091310OS << "#include <arm_bf16.h>\n";1311OS << "#include <arm_vector_types.h>\n";13121313OS << "typedef __SVFloat32_t svfloat32_t;\n";1314OS << "typedef __SVFloat64_t svfloat64_t;\n";1315OS << "typedef __clang_svint8x2_t svint8x2_t;\n";1316OS << "typedef __clang_svint16x2_t svint16x2_t;\n";1317OS << "typedef __clang_svint32x2_t svint32x2_t;\n";1318OS << "typedef __clang_svint64x2_t svint64x2_t;\n";1319OS << "typedef __clang_svuint8x2_t svuint8x2_t;\n";1320OS << "typedef __clang_svuint16x2_t svuint16x2_t;\n";1321OS << "typedef __clang_svuint32x2_t svuint32x2_t;\n";1322OS << "typedef __clang_svuint64x2_t svuint64x2_t;\n";1323OS << "typedef __clang_svfloat16x2_t svfloat16x2_t;\n";1324OS << "typedef __clang_svfloat32x2_t svfloat32x2_t;\n";1325OS << "typedef __clang_svfloat64x2_t svfloat64x2_t;\n";1326OS << "typedef __clang_svint8x3_t svint8x3_t;\n";1327OS << "typedef __clang_svint16x3_t svint16x3_t;\n";1328OS << "typedef __clang_svint32x3_t svint32x3_t;\n";1329OS << "typedef __clang_svint64x3_t svint64x3_t;\n";1330OS << "typedef __clang_svuint8x3_t svuint8x3_t;\n";1331OS << "typedef __clang_svuint16x3_t svuint16x3_t;\n";1332OS << "typedef __clang_svuint32x3_t svuint32x3_t;\n";1333OS << "typedef __clang_svuint64x3_t svuint64x3_t;\n";1334OS << "typedef __clang_svfloat16x3_t svfloat16x3_t;\n";1335OS << "typedef __clang_svfloat32x3_t svfloat32x3_t;\n";1336OS << "typedef __clang_svfloat64x3_t svfloat64x3_t;\n";1337OS << "typedef __clang_svint8x4_t svint8x4_t;\n";1338OS << "typedef __clang_svint16x4_t svint16x4_t;\n";1339OS << "typedef __clang_svint32x4_t svint32x4_t;\n";1340OS << "typedef __clang_svint64x4_t svint64x4_t;\n";1341OS << "typedef __clang_svuint8x4_t svuint8x4_t;\n";1342OS << "typedef __clang_svuint16x4_t svuint16x4_t;\n";1343OS << "typedef __clang_svuint32x4_t svuint32x4_t;\n";1344OS << "typedef __clang_svuint64x4_t svuint64x4_t;\n";1345OS << "typedef __clang_svfloat16x4_t svfloat16x4_t;\n";1346OS << "typedef __clang_svfloat32x4_t svfloat32x4_t;\n";1347OS << "typedef __clang_svfloat64x4_t svfloat64x4_t;\n";1348OS << "typedef __SVBool_t svbool_t;\n";1349OS << "typedef __clang_svboolx2_t svboolx2_t;\n";1350OS << "typedef __clang_svboolx4_t svboolx4_t;\n\n";13511352OS << "typedef __clang_svbfloat16x2_t svbfloat16x2_t;\n";1353OS << "typedef __clang_svbfloat16x3_t svbfloat16x3_t;\n";1354OS << "typedef __clang_svbfloat16x4_t svbfloat16x4_t;\n";13551356OS << "typedef __SVCount_t svcount_t;\n\n";13571358OS << "enum svpattern\n";1359OS << "{\n";1360OS << " SV_POW2 = 0,\n";1361OS << " SV_VL1 = 1,\n";1362OS << " SV_VL2 = 2,\n";1363OS << " SV_VL3 = 3,\n";1364OS << " SV_VL4 = 4,\n";1365OS << " SV_VL5 = 5,\n";1366OS << " SV_VL6 = 6,\n";1367OS << " SV_VL7 = 7,\n";1368OS << " SV_VL8 = 8,\n";1369OS << " SV_VL16 = 9,\n";1370OS << " SV_VL32 = 10,\n";1371OS << " SV_VL64 = 11,\n";1372OS << " SV_VL128 = 12,\n";1373OS << " SV_VL256 = 13,\n";1374OS << " SV_MUL4 = 29,\n";1375OS << " SV_MUL3 = 30,\n";1376OS << " SV_ALL = 31\n";1377OS << "};\n\n";13781379OS << "enum svprfop\n";1380OS << "{\n";1381OS << " SV_PLDL1KEEP = 0,\n";1382OS << " SV_PLDL1STRM = 1,\n";1383OS << " SV_PLDL2KEEP = 2,\n";1384OS << " SV_PLDL2STRM = 3,\n";1385OS << " SV_PLDL3KEEP = 4,\n";1386OS << " SV_PLDL3STRM = 5,\n";1387OS << " SV_PSTL1KEEP = 8,\n";1388OS << " SV_PSTL1STRM = 9,\n";1389OS << " SV_PSTL2KEEP = 10,\n";1390OS << " SV_PSTL2STRM = 11,\n";1391OS << " SV_PSTL3KEEP = 12,\n";1392OS << " SV_PSTL3STRM = 13\n";1393OS << "};\n\n";13941395OS << "/* Function attributes */\n";1396OS << "#define __ai static __inline__ __attribute__((__always_inline__, "1397"__nodebug__))\n\n";1398OS << "#define __aio static __inline__ __attribute__((__always_inline__, "1399"__nodebug__, __overloadable__))\n\n";14001401// Add reinterpret functions.1402for (auto [N, Suffix] :1403std::initializer_list<std::pair<unsigned, const char *>>{1404{1, ""}, {2, "_x2"}, {3, "_x3"}, {4, "_x4"}}) {1405for (auto ShortForm : {false, true})1406for (const ReinterpretTypeInfo &To : Reinterprets) {1407SVEType ToV(To.BaseType, N);1408for (const ReinterpretTypeInfo &From : Reinterprets) {1409SVEType FromV(From.BaseType, N);1410OS << "__aio "1411"__attribute__((__clang_arm_builtin_alias(__builtin_sve_"1412"reinterpret_"1413<< To.Suffix << "_" << From.Suffix << Suffix << ")))\n"1414<< ToV.str() << " svreinterpret_" << To.Suffix;1415if (!ShortForm)1416OS << "_" << From.Suffix << Suffix;1417OS << "(" << FromV.str() << " op);\n";1418}1419}1420}14211422createCoreHeaderIntrinsics(OS, *this, ACLEKind::SVE);14231424OS << "#define svcvtnt_bf16_x svcvtnt_bf16_m\n";1425OS << "#define svcvtnt_bf16_f32_x svcvtnt_bf16_f32_m\n";14261427OS << "#define svcvtnt_f16_x svcvtnt_f16_m\n";1428OS << "#define svcvtnt_f16_f32_x svcvtnt_f16_f32_m\n";1429OS << "#define svcvtnt_f32_x svcvtnt_f32_m\n";1430OS << "#define svcvtnt_f32_f64_x svcvtnt_f32_f64_m\n\n";14311432OS << "#define svcvtxnt_f32_x svcvtxnt_f32_m\n";1433OS << "#define svcvtxnt_f32_f64_x svcvtxnt_f32_f64_m\n\n";14341435OS << "#ifdef __cplusplus\n";1436OS << "} // extern \"C\"\n";1437OS << "#endif\n\n";1438OS << "#undef __ai\n\n";1439OS << "#undef __aio\n\n";1440OS << "#endif /* __ARM_SVE_H */\n";1441}14421443void SVEEmitter::createBuiltins(raw_ostream &OS) {1444std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");1445SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;1446for (auto *R : RV)1447createIntrinsic(R, Defs);14481449// The mappings must be sorted based on BuiltinID.1450llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,1451const std::unique_ptr<Intrinsic> &B) {1452return A->getMangledName() < B->getMangledName();1453});14541455OS << "#ifdef GET_SVE_BUILTINS\n";1456for (auto &Def : Defs) {1457// Only create BUILTINs for non-overloaded intrinsics, as overloaded1458// declarations only live in the header file.1459if (Def->getClassKind() != ClassG) {1460OS << "TARGET_BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \""1461<< Def->getBuiltinTypeStr() << "\", \"n\", \"";1462Def->printGuard(OS);1463OS << "\")\n";1464}1465}14661467// Add reinterpret functions.1468for (auto [N, Suffix] :1469std::initializer_list<std::pair<unsigned, const char *>>{1470{1, ""}, {2, "_x2"}, {3, "_x3"}, {4, "_x4"}}) {1471for (const ReinterpretTypeInfo &To : Reinterprets) {1472SVEType ToV(To.BaseType, N);1473for (const ReinterpretTypeInfo &From : Reinterprets) {1474SVEType FromV(From.BaseType, N);1475OS << "TARGET_BUILTIN(__builtin_sve_reinterpret_" << To.Suffix << "_"1476<< From.Suffix << Suffix << +", \"" << ToV.builtin_str()1477<< FromV.builtin_str() << "\", \"n\", \"sme|sve\")\n";1478}1479}1480}14811482OS << "#endif\n\n";1483}14841485void SVEEmitter::createCodeGenMap(raw_ostream &OS) {1486std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");1487SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;1488for (auto *R : RV)1489createIntrinsic(R, Defs);14901491// The mappings must be sorted based on BuiltinID.1492llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,1493const std::unique_ptr<Intrinsic> &B) {1494return A->getMangledName() < B->getMangledName();1495});14961497OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n";1498for (auto &Def : Defs) {1499// Builtins only exist for non-overloaded intrinsics, overloaded1500// declarations only live in the header file.1501if (Def->getClassKind() == ClassG)1502continue;15031504uint64_t Flags = Def->getFlags();1505auto FlagString = std::to_string(Flags);15061507std::string LLVMName = Def->getMangledLLVMName();1508std::string Builtin = Def->getMangledName();1509if (!LLVMName.empty())1510OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString1511<< "),\n";1512else1513OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n";1514}1515OS << "#endif\n\n";1516}15171518void SVEEmitter::createRangeChecks(raw_ostream &OS) {1519std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");1520SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;1521for (auto *R : RV)1522createIntrinsic(R, Defs);15231524// The mappings must be sorted based on BuiltinID.1525llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,1526const std::unique_ptr<Intrinsic> &B) {1527return A->getMangledName() < B->getMangledName();1528});152915301531OS << "#ifdef GET_SVE_IMMEDIATE_CHECK\n";15321533// Ensure these are only emitted once.1534std::set<std::string> Emitted;15351536for (auto &Def : Defs) {1537if (Emitted.find(Def->getMangledName()) != Emitted.end() ||1538Def->getImmChecks().empty())1539continue;15401541OS << "case SVE::BI__builtin_sve_" << Def->getMangledName() << ":\n";1542for (auto &Check : Def->getImmChecks())1543OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", "1544<< Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n";1545OS << " break;\n";15461547Emitted.insert(Def->getMangledName());1548}15491550OS << "#endif\n\n";1551}15521553/// Create the SVETypeFlags used in CGBuiltins1554void SVEEmitter::createTypeFlags(raw_ostream &OS) {1555OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n";1556for (auto &KV : FlagTypes)1557OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n";1558OS << "#endif\n\n";15591560OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n";1561for (auto &KV : EltTypes)1562OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";1563OS << "#endif\n\n";15641565OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n";1566for (auto &KV : MemEltTypes)1567OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";1568OS << "#endif\n\n";15691570OS << "#ifdef LLVM_GET_SVE_MERGETYPES\n";1571for (auto &KV : MergeTypes)1572OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";1573OS << "#endif\n\n";15741575OS << "#ifdef LLVM_GET_SVE_IMMCHECKTYPES\n";1576for (auto &KV : ImmCheckTypes)1577OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";1578OS << "#endif\n\n";1579}15801581void SVEEmitter::createSMEHeader(raw_ostream &OS) {1582OS << "/*===---- arm_sme.h - ARM SME intrinsics "1583"------===\n"1584" *\n"1585" *\n"1586" * Part of the LLVM Project, under the Apache License v2.0 with LLVM "1587"Exceptions.\n"1588" * See https://llvm.org/LICENSE.txt for license information.\n"1589" * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"1590" *\n"1591" *===-----------------------------------------------------------------"1592"------===\n"1593" */\n\n";15941595OS << "#ifndef __ARM_SME_H\n";1596OS << "#define __ARM_SME_H\n\n";15971598OS << "#if !defined(__LITTLE_ENDIAN__)\n";1599OS << "#error \"Big endian is currently not supported for arm_sme.h\"\n";1600OS << "#endif\n";16011602OS << "#include <arm_sve.h>\n\n";1603OS << "#include <stddef.h>\n\n";16041605OS << "/* Function attributes */\n";1606OS << "#define __ai static __inline__ __attribute__((__always_inline__, "1607"__nodebug__))\n\n";1608OS << "#define __aio static __inline__ __attribute__((__always_inline__, "1609"__nodebug__, __overloadable__))\n\n";16101611OS << "#ifdef __cplusplus\n";1612OS << "extern \"C\" {\n";1613OS << "#endif\n\n";16141615OS << "void __arm_za_disable(void) __arm_streaming_compatible;\n\n";16161617OS << "__ai bool __arm_has_sme(void) __arm_streaming_compatible {\n";1618OS << " uint64_t x0, x1;\n";1619OS << " __builtin_arm_get_sme_state(&x0, &x1);\n";1620OS << " return x0 & (1ULL << 63);\n";1621OS << "}\n\n";16221623OS << "__ai bool __arm_in_streaming_mode(void) __arm_streaming_compatible "1624"{\n";1625OS << " uint64_t x0, x1;\n";1626OS << " __builtin_arm_get_sme_state(&x0, &x1);\n";1627OS << " return x0 & 1;\n";1628OS << "}\n\n";16291630OS << "void *__arm_sc_memcpy(void *dest, const void *src, size_t n) __arm_streaming_compatible;\n";1631OS << "void *__arm_sc_memmove(void *dest, const void *src, size_t n) __arm_streaming_compatible;\n";1632OS << "void *__arm_sc_memset(void *s, int c, size_t n) __arm_streaming_compatible;\n";1633OS << "void *__arm_sc_memchr(void *s, int c, size_t n) __arm_streaming_compatible;\n\n";16341635OS << "__ai __attribute__((target(\"sme\"))) void svundef_za(void) "1636"__arm_streaming_compatible __arm_out(\"za\") "1637"{ }\n\n";16381639createCoreHeaderIntrinsics(OS, *this, ACLEKind::SME);16401641OS << "#ifdef __cplusplus\n";1642OS << "} // extern \"C\"\n";1643OS << "#endif\n\n";1644OS << "#undef __ai\n\n";1645OS << "#endif /* __ARM_SME_H */\n";1646}16471648void SVEEmitter::createSMEBuiltins(raw_ostream &OS) {1649std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");1650SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;1651for (auto *R : RV) {1652createIntrinsic(R, Defs);1653}16541655// The mappings must be sorted based on BuiltinID.1656llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,1657const std::unique_ptr<Intrinsic> &B) {1658return A->getMangledName() < B->getMangledName();1659});16601661OS << "#ifdef GET_SME_BUILTINS\n";1662for (auto &Def : Defs) {1663// Only create BUILTINs for non-overloaded intrinsics, as overloaded1664// declarations only live in the header file.1665if (Def->getClassKind() != ClassG) {1666OS << "TARGET_BUILTIN(__builtin_sme_" << Def->getMangledName() << ", \""1667<< Def->getBuiltinTypeStr() << "\", \"n\", \"";1668Def->printGuard(OS);1669OS << "\")\n";1670}1671}16721673OS << "#endif\n\n";1674}16751676void SVEEmitter::createSMECodeGenMap(raw_ostream &OS) {1677std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");1678SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;1679for (auto *R : RV) {1680createIntrinsic(R, Defs);1681}16821683// The mappings must be sorted based on BuiltinID.1684llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,1685const std::unique_ptr<Intrinsic> &B) {1686return A->getMangledName() < B->getMangledName();1687});16881689OS << "#ifdef GET_SME_LLVM_INTRINSIC_MAP\n";1690for (auto &Def : Defs) {1691// Builtins only exist for non-overloaded intrinsics, overloaded1692// declarations only live in the header file.1693if (Def->getClassKind() == ClassG)1694continue;16951696uint64_t Flags = Def->getFlags();1697auto FlagString = std::to_string(Flags);16981699std::string LLVMName = Def->getLLVMName();1700std::string Builtin = Def->getMangledName();1701if (!LLVMName.empty())1702OS << "SMEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString1703<< "),\n";1704else1705OS << "SMEMAP2(" << Builtin << ", " << FlagString << "),\n";1706}1707OS << "#endif\n\n";1708}17091710void SVEEmitter::createSMERangeChecks(raw_ostream &OS) {1711std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");1712SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;1713for (auto *R : RV) {1714createIntrinsic(R, Defs);1715}17161717// The mappings must be sorted based on BuiltinID.1718llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,1719const std::unique_ptr<Intrinsic> &B) {1720return A->getMangledName() < B->getMangledName();1721});172217231724OS << "#ifdef GET_SME_IMMEDIATE_CHECK\n";17251726// Ensure these are only emitted once.1727std::set<std::string> Emitted;17281729for (auto &Def : Defs) {1730if (Emitted.find(Def->getMangledName()) != Emitted.end() ||1731Def->getImmChecks().empty())1732continue;17331734OS << "case SME::BI__builtin_sme_" << Def->getMangledName() << ":\n";1735for (auto &Check : Def->getImmChecks())1736OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", "1737<< Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n";1738OS << " break;\n";17391740Emitted.insert(Def->getMangledName());1741}17421743OS << "#endif\n\n";1744}17451746void SVEEmitter::createBuiltinZAState(raw_ostream &OS) {1747std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");1748SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;1749for (auto *R : RV)1750createIntrinsic(R, Defs);17511752std::map<std::string, std::set<std::string>> IntrinsicsPerState;1753for (auto &Def : Defs) {1754std::string Key;1755auto AddToKey = [&Key](const std::string &S) -> void {1756Key = Key.empty() ? S : (Key + " | " + S);1757};17581759if (Def->isFlagSet(getEnumValueForFlag("IsInZA")))1760AddToKey("ArmInZA");1761else if (Def->isFlagSet(getEnumValueForFlag("IsOutZA")))1762AddToKey("ArmOutZA");1763else if (Def->isFlagSet(getEnumValueForFlag("IsInOutZA")))1764AddToKey("ArmInOutZA");17651766if (Def->isFlagSet(getEnumValueForFlag("IsInZT0")))1767AddToKey("ArmInZT0");1768else if (Def->isFlagSet(getEnumValueForFlag("IsOutZT0")))1769AddToKey("ArmOutZT0");1770else if (Def->isFlagSet(getEnumValueForFlag("IsInOutZT0")))1771AddToKey("ArmInOutZT0");17721773if (!Key.empty())1774IntrinsicsPerState[Key].insert(Def->getMangledName());1775}17761777OS << "#ifdef GET_SME_BUILTIN_GET_STATE\n";1778for (auto &KV : IntrinsicsPerState) {1779for (StringRef Name : KV.second)1780OS << "case SME::BI__builtin_sme_" << Name << ":\n";1781OS << " return " << KV.first << ";\n";1782}1783OS << "#endif\n\n";1784}17851786void SVEEmitter::createStreamingAttrs(raw_ostream &OS, ACLEKind Kind) {1787std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");1788SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;1789for (auto *R : RV)1790createIntrinsic(R, Defs);17911792StringRef ExtensionKind;1793switch (Kind) {1794case ACLEKind::SME:1795ExtensionKind = "SME";1796break;1797case ACLEKind::SVE:1798ExtensionKind = "SVE";1799break;1800}18011802OS << "#ifdef GET_" << ExtensionKind << "_STREAMING_ATTRS\n";18031804llvm::StringMap<std::set<std::string>> StreamingMap;18051806uint64_t IsStreamingFlag = getEnumValueForFlag("IsStreaming");1807uint64_t VerifyRuntimeMode = getEnumValueForFlag("VerifyRuntimeMode");1808uint64_t IsStreamingCompatibleFlag =1809getEnumValueForFlag("IsStreamingCompatible");18101811for (auto &Def : Defs) {1812if (!Def->isFlagSet(VerifyRuntimeMode) && !Def->getSVEGuard().empty() &&1813!Def->getSMEGuard().empty())1814report_fatal_error("Missing VerifyRuntimeMode flag");18151816if (Def->isFlagSet(IsStreamingFlag))1817StreamingMap["ArmStreaming"].insert(Def->getMangledName());1818else if (Def->isFlagSet(VerifyRuntimeMode))1819StreamingMap["VerifyRuntimeMode"].insert(Def->getMangledName());1820else if (Def->isFlagSet(IsStreamingCompatibleFlag))1821StreamingMap["ArmStreamingCompatible"].insert(Def->getMangledName());1822else1823StreamingMap["ArmNonStreaming"].insert(Def->getMangledName());1824}18251826for (auto BuiltinType : StreamingMap.keys()) {1827for (auto Name : StreamingMap[BuiltinType]) {1828OS << "case " << ExtensionKind << "::BI__builtin_"1829<< ExtensionKind.lower() << "_";1830OS << Name << ":\n";1831}1832OS << " BuiltinType = " << BuiltinType << ";\n";1833OS << " break;\n";1834}18351836OS << "#endif\n\n";1837}18381839namespace clang {1840void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) {1841SVEEmitter(Records).createHeader(OS);1842}18431844void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) {1845SVEEmitter(Records).createBuiltins(OS);1846}18471848void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {1849SVEEmitter(Records).createCodeGenMap(OS);1850}18511852void EmitSveRangeChecks(RecordKeeper &Records, raw_ostream &OS) {1853SVEEmitter(Records).createRangeChecks(OS);1854}18551856void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) {1857SVEEmitter(Records).createTypeFlags(OS);1858}18591860void EmitSveStreamingAttrs(RecordKeeper &Records, raw_ostream &OS) {1861SVEEmitter(Records).createStreamingAttrs(OS, ACLEKind::SVE);1862}18631864void EmitSmeHeader(RecordKeeper &Records, raw_ostream &OS) {1865SVEEmitter(Records).createSMEHeader(OS);1866}18671868void EmitSmeBuiltins(RecordKeeper &Records, raw_ostream &OS) {1869SVEEmitter(Records).createSMEBuiltins(OS);1870}18711872void EmitSmeBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {1873SVEEmitter(Records).createSMECodeGenMap(OS);1874}18751876void EmitSmeRangeChecks(RecordKeeper &Records, raw_ostream &OS) {1877SVEEmitter(Records).createSMERangeChecks(OS);1878}18791880void EmitSmeStreamingAttrs(RecordKeeper &Records, raw_ostream &OS) {1881SVEEmitter(Records).createStreamingAttrs(OS, ACLEKind::SME);1882}18831884void EmitSmeBuiltinZAState(RecordKeeper &Records, raw_ostream &OS) {1885SVEEmitter(Records).createBuiltinZAState(OS);1886}1887} // End namespace clang188818891890