xref: /freebsd-src/contrib/llvm-project/clang/utils/TableGen/SveEmitter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15ffd83dbSDimitry Andric //===- SveEmitter.cpp - Generate arm_sve.h for use with clang -*- C++ -*-===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric //  Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric //  See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric //  SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric //
95ffd83dbSDimitry Andric // This tablegen backend is responsible for emitting arm_sve.h, which includes
105ffd83dbSDimitry Andric // a declaration and definition of each function specified by the ARM C/C++
115ffd83dbSDimitry Andric // Language Extensions (ACLE).
125ffd83dbSDimitry Andric //
135ffd83dbSDimitry Andric // For details, visit:
145ffd83dbSDimitry Andric //  https://developer.arm.com/architectures/system-architectures/software-standards/acle
155ffd83dbSDimitry Andric //
165ffd83dbSDimitry Andric // Each SVE instruction is implemented in terms of 1 or more functions which
175ffd83dbSDimitry Andric // are suffixed with the element type of the input vectors.  Functions may be
185ffd83dbSDimitry Andric // implemented in terms of generic vector operations such as +, *, -, etc. or
195ffd83dbSDimitry Andric // by calling a __builtin_-prefixed function which will be handled by clang's
205ffd83dbSDimitry Andric // CodeGen library.
215ffd83dbSDimitry Andric //
225ffd83dbSDimitry Andric // See also the documentation in include/clang/Basic/arm_sve.td.
235ffd83dbSDimitry Andric //
245ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
255ffd83dbSDimitry Andric 
265ffd83dbSDimitry Andric #include "llvm/ADT/ArrayRef.h"
275f757f3fSDimitry Andric #include "llvm/ADT/STLExtras.h"
285ffd83dbSDimitry Andric #include "llvm/ADT/StringExtras.h"
295f757f3fSDimitry Andric #include "llvm/ADT/StringMap.h"
305ffd83dbSDimitry Andric #include "llvm/TableGen/Error.h"
315f757f3fSDimitry Andric #include "llvm/TableGen/Record.h"
325f757f3fSDimitry Andric #include <array>
335ffd83dbSDimitry Andric #include <cctype>
345f757f3fSDimitry Andric #include <set>
355f757f3fSDimitry Andric #include <sstream>
365f757f3fSDimitry Andric #include <string>
375ffd83dbSDimitry Andric #include <tuple>
385ffd83dbSDimitry Andric 
395ffd83dbSDimitry Andric using namespace llvm;
405ffd83dbSDimitry Andric 
415ffd83dbSDimitry Andric enum ClassKind {
425ffd83dbSDimitry Andric   ClassNone,
435ffd83dbSDimitry Andric   ClassS,     // signed/unsigned, e.g., "_s8", "_u8" suffix
445ffd83dbSDimitry Andric   ClassG,     // Overloaded name without type suffix
455ffd83dbSDimitry Andric };
465ffd83dbSDimitry Andric 
475f757f3fSDimitry Andric enum class ACLEKind { SVE, SME };
485f757f3fSDimitry Andric 
495ffd83dbSDimitry Andric using TypeSpec = std::string;
505ffd83dbSDimitry Andric 
515ffd83dbSDimitry Andric namespace {
525ffd83dbSDimitry Andric 
535ffd83dbSDimitry Andric class ImmCheck {
545ffd83dbSDimitry Andric   unsigned Arg;
555ffd83dbSDimitry Andric   unsigned Kind;
565ffd83dbSDimitry Andric   unsigned ElementSizeInBits;
575ffd83dbSDimitry Andric 
585ffd83dbSDimitry Andric public:
595ffd83dbSDimitry Andric   ImmCheck(unsigned Arg, unsigned Kind, unsigned ElementSizeInBits = 0)
605ffd83dbSDimitry Andric       : Arg(Arg), Kind(Kind), ElementSizeInBits(ElementSizeInBits) {}
615ffd83dbSDimitry Andric   ImmCheck(const ImmCheck &Other) = default;
625ffd83dbSDimitry Andric   ~ImmCheck() = default;
635ffd83dbSDimitry Andric 
645ffd83dbSDimitry Andric   unsigned getArg() const { return Arg; }
655ffd83dbSDimitry Andric   unsigned getKind() const { return Kind; }
665ffd83dbSDimitry Andric   unsigned getElementSizeInBits() const { return ElementSizeInBits; }
675ffd83dbSDimitry Andric };
685ffd83dbSDimitry Andric 
695ffd83dbSDimitry Andric class SVEType {
705ffd83dbSDimitry Andric   bool Float, Signed, Immediate, Void, Constant, Pointer, BFloat;
7106c3fb27SDimitry Andric   bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp,
7206c3fb27SDimitry Andric       Svcount;
735ffd83dbSDimitry Andric   unsigned Bitwidth, ElementBitwidth, NumVectors;
745ffd83dbSDimitry Andric 
755ffd83dbSDimitry Andric public:
765f757f3fSDimitry Andric   SVEType() : SVEType("", 'v') {}
775ffd83dbSDimitry Andric 
785f757f3fSDimitry Andric   SVEType(StringRef TS, char CharMod, unsigned NumVectors = 1)
795f757f3fSDimitry Andric       : Float(false), Signed(true), Immediate(false), Void(false),
805ffd83dbSDimitry Andric         Constant(false), Pointer(false), BFloat(false), DefaultType(false),
815ffd83dbSDimitry Andric         IsScalable(true), Predicate(false), PredicatePattern(false),
8206c3fb27SDimitry Andric         PrefetchOp(false), Svcount(false), Bitwidth(128), ElementBitwidth(~0U),
835f757f3fSDimitry Andric         NumVectors(NumVectors) {
845ffd83dbSDimitry Andric     if (!TS.empty())
855f757f3fSDimitry Andric       applyTypespec(TS);
865ffd83dbSDimitry Andric     applyModifier(CharMod);
875ffd83dbSDimitry Andric   }
885ffd83dbSDimitry Andric 
895f757f3fSDimitry Andric   SVEType(const SVEType &Base, unsigned NumV) : SVEType(Base) {
905f757f3fSDimitry Andric     NumVectors = NumV;
915f757f3fSDimitry Andric   }
925f757f3fSDimitry Andric 
935ffd83dbSDimitry Andric   bool isPointer() const { return Pointer; }
945ffd83dbSDimitry Andric   bool isVoidPointer() const { return Pointer && Void; }
955ffd83dbSDimitry Andric   bool isSigned() const { return Signed; }
965ffd83dbSDimitry Andric   bool isImmediate() const { return Immediate; }
975ffd83dbSDimitry Andric   bool isScalar() const { return NumVectors == 0; }
985ffd83dbSDimitry Andric   bool isVector() const { return NumVectors > 0; }
995ffd83dbSDimitry Andric   bool isScalableVector() const { return isVector() && IsScalable; }
1005f757f3fSDimitry Andric   bool isFixedLengthVector() const { return isVector() && !IsScalable; }
1015ffd83dbSDimitry Andric   bool isChar() const { return ElementBitwidth == 8; }
102*0fca6ea1SDimitry Andric   bool isVoid() const { return Void && !Pointer; }
1035ffd83dbSDimitry Andric   bool isDefault() const { return DefaultType; }
1045ffd83dbSDimitry Andric   bool isFloat() const { return Float && !BFloat; }
1055ffd83dbSDimitry Andric   bool isBFloat() const { return BFloat && !Float; }
1065ffd83dbSDimitry Andric   bool isFloatingPoint() const { return Float || BFloat; }
10706c3fb27SDimitry Andric   bool isInteger() const {
10806c3fb27SDimitry Andric     return !isFloatingPoint() && !Predicate && !Svcount;
10906c3fb27SDimitry Andric   }
1105ffd83dbSDimitry Andric   bool isScalarPredicate() const {
1115ffd83dbSDimitry Andric     return !isFloatingPoint() && Predicate && NumVectors == 0;
1125ffd83dbSDimitry Andric   }
1135ffd83dbSDimitry Andric   bool isPredicateVector() const { return Predicate; }
1145ffd83dbSDimitry Andric   bool isPredicatePattern() const { return PredicatePattern; }
1155ffd83dbSDimitry Andric   bool isPrefetchOp() const { return PrefetchOp; }
11606c3fb27SDimitry Andric   bool isSvcount() const { return Svcount; }
1175ffd83dbSDimitry Andric   bool isConstant() const { return Constant; }
1185ffd83dbSDimitry Andric   unsigned getElementSizeInBits() const { return ElementBitwidth; }
1195ffd83dbSDimitry Andric   unsigned getNumVectors() const { return NumVectors; }
1205ffd83dbSDimitry Andric 
1215ffd83dbSDimitry Andric   unsigned getNumElements() const {
1225ffd83dbSDimitry Andric     assert(ElementBitwidth != ~0U);
1235ffd83dbSDimitry Andric     return Bitwidth / ElementBitwidth;
1245ffd83dbSDimitry Andric   }
1255ffd83dbSDimitry Andric   unsigned getSizeInBits() const {
1265ffd83dbSDimitry Andric     return Bitwidth;
1275ffd83dbSDimitry Andric   }
1285ffd83dbSDimitry Andric 
1295ffd83dbSDimitry Andric   /// Return the string representation of a type, which is an encoded
1305ffd83dbSDimitry Andric   /// string for passing to the BUILTIN() macro in Builtins.def.
1315ffd83dbSDimitry Andric   std::string builtin_str() const;
1325ffd83dbSDimitry Andric 
1335ffd83dbSDimitry Andric   /// Return the C/C++ string representation of a type for use in the
1345ffd83dbSDimitry Andric   /// arm_sve.h header file.
1355ffd83dbSDimitry Andric   std::string str() const;
1365ffd83dbSDimitry Andric 
1375ffd83dbSDimitry Andric private:
1385ffd83dbSDimitry Andric   /// Creates the type based on the typespec string in TS.
1395f757f3fSDimitry Andric   void applyTypespec(StringRef TS);
1405ffd83dbSDimitry Andric 
1415ffd83dbSDimitry Andric   /// Applies a prototype modifier to the type.
1425ffd83dbSDimitry Andric   void applyModifier(char Mod);
1435ffd83dbSDimitry Andric };
1445ffd83dbSDimitry Andric 
1455ffd83dbSDimitry Andric class SVEEmitter;
1465ffd83dbSDimitry Andric 
1475ffd83dbSDimitry Andric /// The main grunt class. This represents an instantiation of an intrinsic with
1485ffd83dbSDimitry Andric /// a particular typespec and prototype.
1495ffd83dbSDimitry Andric class Intrinsic {
1505ffd83dbSDimitry Andric   /// The unmangled name.
1515ffd83dbSDimitry Andric   std::string Name;
1525ffd83dbSDimitry Andric 
1535ffd83dbSDimitry Andric   /// The name of the corresponding LLVM IR intrinsic.
1545ffd83dbSDimitry Andric   std::string LLVMName;
1555ffd83dbSDimitry Andric 
1565ffd83dbSDimitry Andric   /// Intrinsic prototype.
1575ffd83dbSDimitry Andric   std::string Proto;
1585ffd83dbSDimitry Andric 
1595ffd83dbSDimitry Andric   /// The base type spec for this intrinsic.
1605ffd83dbSDimitry Andric   TypeSpec BaseTypeSpec;
1615ffd83dbSDimitry Andric 
1625ffd83dbSDimitry Andric   /// The base class kind. Most intrinsics use ClassS, which has full type
1635ffd83dbSDimitry Andric   /// info for integers (_s32/_u32), or ClassG which is used for overloaded
1645ffd83dbSDimitry Andric   /// intrinsics.
1655ffd83dbSDimitry Andric   ClassKind Class;
1665ffd83dbSDimitry Andric 
1675ffd83dbSDimitry Andric   /// The architectural #ifdef guard.
168*0fca6ea1SDimitry Andric   std::string SVEGuard, SMEGuard;
1695ffd83dbSDimitry Andric 
1705ffd83dbSDimitry Andric   // The merge suffix such as _m, _x or _z.
1715ffd83dbSDimitry Andric   std::string MergeSuffix;
1725ffd83dbSDimitry Andric 
1735ffd83dbSDimitry Andric   /// The types of return value [0] and parameters [1..].
1745ffd83dbSDimitry Andric   std::vector<SVEType> Types;
1755ffd83dbSDimitry Andric 
1765ffd83dbSDimitry Andric   /// The "base type", which is VarType('d', BaseTypeSpec).
1775ffd83dbSDimitry Andric   SVEType BaseType;
1785ffd83dbSDimitry Andric 
1795ffd83dbSDimitry Andric   uint64_t Flags;
1805ffd83dbSDimitry Andric 
1815ffd83dbSDimitry Andric   SmallVector<ImmCheck, 2> ImmChecks;
1825ffd83dbSDimitry Andric 
1835ffd83dbSDimitry Andric public:
1845ffd83dbSDimitry Andric   Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
1855ffd83dbSDimitry Andric             StringRef MergeSuffix, uint64_t MemoryElementTy, StringRef LLVMName,
1865ffd83dbSDimitry Andric             uint64_t Flags, ArrayRef<ImmCheck> ImmChecks, TypeSpec BT,
187*0fca6ea1SDimitry Andric             ClassKind Class, SVEEmitter &Emitter, StringRef SVEGuard,
188*0fca6ea1SDimitry Andric             StringRef SMEGuard);
1895ffd83dbSDimitry Andric 
1905ffd83dbSDimitry Andric   ~Intrinsic()=default;
1915ffd83dbSDimitry Andric 
1925ffd83dbSDimitry Andric   std::string getName() const { return Name; }
1935ffd83dbSDimitry Andric   std::string getLLVMName() const { return LLVMName; }
1945ffd83dbSDimitry Andric   std::string getProto() const { return Proto; }
1955ffd83dbSDimitry Andric   TypeSpec getBaseTypeSpec() const { return BaseTypeSpec; }
1965ffd83dbSDimitry Andric   SVEType getBaseType() const { return BaseType; }
1975ffd83dbSDimitry Andric 
198*0fca6ea1SDimitry Andric   StringRef getSVEGuard() const { return SVEGuard; }
199*0fca6ea1SDimitry Andric   StringRef getSMEGuard() const { return SMEGuard; }
200*0fca6ea1SDimitry Andric   void printGuard(raw_ostream &OS) const {
201*0fca6ea1SDimitry Andric     if (!SVEGuard.empty() && SMEGuard.empty())
202*0fca6ea1SDimitry Andric       OS << SVEGuard;
203*0fca6ea1SDimitry Andric     else if (SVEGuard.empty() && !SMEGuard.empty())
204*0fca6ea1SDimitry Andric       OS << SMEGuard;
205*0fca6ea1SDimitry Andric     else {
206*0fca6ea1SDimitry Andric       if (SVEGuard.find(",") != std::string::npos ||
207*0fca6ea1SDimitry Andric           SVEGuard.find("|") != std::string::npos)
208*0fca6ea1SDimitry Andric         OS << "(" << SVEGuard << ")";
209*0fca6ea1SDimitry Andric       else
210*0fca6ea1SDimitry Andric         OS << SVEGuard;
211*0fca6ea1SDimitry Andric       OS << "|";
212*0fca6ea1SDimitry Andric       if (SMEGuard.find(",") != std::string::npos ||
213*0fca6ea1SDimitry Andric           SMEGuard.find("|") != std::string::npos)
214*0fca6ea1SDimitry Andric         OS << "(" << SMEGuard << ")";
215*0fca6ea1SDimitry Andric       else
216*0fca6ea1SDimitry Andric         OS << SMEGuard;
217*0fca6ea1SDimitry Andric     }
218*0fca6ea1SDimitry Andric   }
2195ffd83dbSDimitry Andric   ClassKind getClassKind() const { return Class; }
2205ffd83dbSDimitry Andric 
2215ffd83dbSDimitry Andric   SVEType getReturnType() const { return Types[0]; }
2225ffd83dbSDimitry Andric   ArrayRef<SVEType> getTypes() const { return Types; }
2235ffd83dbSDimitry Andric   SVEType getParamType(unsigned I) const { return Types[I + 1]; }
2245f757f3fSDimitry Andric   unsigned getNumParams() const {
2255f757f3fSDimitry Andric     return Proto.size() - (2 * llvm::count(Proto, '.')) - 1;
2265f757f3fSDimitry Andric   }
2275ffd83dbSDimitry Andric 
2285ffd83dbSDimitry Andric   uint64_t getFlags() const { return Flags; }
2295ffd83dbSDimitry Andric   bool isFlagSet(uint64_t Flag) const { return Flags & Flag;}
2305ffd83dbSDimitry Andric 
2315ffd83dbSDimitry Andric   ArrayRef<ImmCheck> getImmChecks() const { return ImmChecks; }
2325ffd83dbSDimitry Andric 
2335ffd83dbSDimitry Andric   /// Return the type string for a BUILTIN() macro in Builtins.def.
2345ffd83dbSDimitry Andric   std::string getBuiltinTypeStr();
2355ffd83dbSDimitry Andric 
2365ffd83dbSDimitry Andric   /// Return the name, mangled with type information. The name is mangled for
2375ffd83dbSDimitry Andric   /// ClassS, so will add type suffixes such as _u32/_s32.
2385ffd83dbSDimitry Andric   std::string getMangledName() const { return mangleName(ClassS); }
2395ffd83dbSDimitry Andric 
24006c3fb27SDimitry Andric   /// As above, but mangles the LLVM name instead.
24106c3fb27SDimitry Andric   std::string getMangledLLVMName() const { return mangleLLVMName(); }
24206c3fb27SDimitry Andric 
2435ffd83dbSDimitry Andric   /// Returns true if the intrinsic is overloaded, in that it should also generate
2445ffd83dbSDimitry Andric   /// a short form without the type-specifiers, e.g. 'svld1(..)' instead of
2455ffd83dbSDimitry Andric   /// 'svld1_u32(..)'.
2465ffd83dbSDimitry Andric   static bool isOverloadedIntrinsic(StringRef Name) {
247e8d8bef9SDimitry Andric     auto BrOpen = Name.find('[');
2485ffd83dbSDimitry Andric     auto BrClose = Name.find(']');
2495ffd83dbSDimitry Andric     return BrOpen != std::string::npos && BrClose != std::string::npos;
2505ffd83dbSDimitry Andric   }
2515ffd83dbSDimitry Andric 
2525ffd83dbSDimitry Andric   /// Return true if the intrinsic takes a splat operand.
2535ffd83dbSDimitry Andric   bool hasSplat() const {
2545ffd83dbSDimitry Andric     // These prototype modifiers are described in arm_sve.td.
2555ffd83dbSDimitry Andric     return Proto.find_first_of("ajfrKLR@") != std::string::npos;
2565ffd83dbSDimitry Andric   }
2575ffd83dbSDimitry Andric 
2585ffd83dbSDimitry Andric   /// Return the parameter index of the splat operand.
2595ffd83dbSDimitry Andric   unsigned getSplatIdx() const {
2605f757f3fSDimitry Andric     unsigned I = 1, Param = 0;
2615f757f3fSDimitry Andric     for (; I < Proto.size(); ++I, ++Param) {
2625f757f3fSDimitry Andric       if (Proto[I] == 'a' || Proto[I] == 'j' || Proto[I] == 'f' ||
2635f757f3fSDimitry Andric           Proto[I] == 'r' || Proto[I] == 'K' || Proto[I] == 'L' ||
2645f757f3fSDimitry Andric           Proto[I] == 'R' || Proto[I] == '@')
2655f757f3fSDimitry Andric         break;
2665f757f3fSDimitry Andric 
2675f757f3fSDimitry Andric       // Multivector modifier can be skipped
2685f757f3fSDimitry Andric       if (Proto[I] == '.')
2695f757f3fSDimitry Andric         I += 2;
2705f757f3fSDimitry Andric     }
2715f757f3fSDimitry Andric     assert(I != Proto.size() && "Prototype has no splat operand");
2725f757f3fSDimitry Andric     return Param;
2735ffd83dbSDimitry Andric   }
2745ffd83dbSDimitry Andric 
2755ffd83dbSDimitry Andric   /// Emits the intrinsic declaration to the ostream.
2765f757f3fSDimitry Andric   void emitIntrinsic(raw_ostream &OS, SVEEmitter &Emitter, ACLEKind Kind) const;
2775ffd83dbSDimitry Andric 
2785ffd83dbSDimitry Andric private:
2795ffd83dbSDimitry Andric   std::string getMergeSuffix() const { return MergeSuffix; }
2805ffd83dbSDimitry Andric   std::string mangleName(ClassKind LocalCK) const;
28106c3fb27SDimitry Andric   std::string mangleLLVMName() const;
2825ffd83dbSDimitry Andric   std::string replaceTemplatedArgs(std::string Name, TypeSpec TS,
2835ffd83dbSDimitry Andric                                    std::string Proto) const;
2845ffd83dbSDimitry Andric };
2855ffd83dbSDimitry Andric 
2865ffd83dbSDimitry Andric class SVEEmitter {
2875ffd83dbSDimitry Andric private:
2885ffd83dbSDimitry Andric   // The reinterpret builtins are generated separately because they
2895ffd83dbSDimitry Andric   // need the cross product of all types (121 functions in total),
2905ffd83dbSDimitry Andric   // which is inconvenient to specify in the arm_sve.td file or
2915ffd83dbSDimitry Andric   // generate in CGBuiltin.cpp.
2925ffd83dbSDimitry Andric   struct ReinterpretTypeInfo {
2935f757f3fSDimitry Andric     SVEType BaseType;
2945ffd83dbSDimitry Andric     const char *Suffix;
2955ffd83dbSDimitry Andric   };
2965f757f3fSDimitry Andric 
2975f757f3fSDimitry Andric   static const std::array<ReinterpretTypeInfo, 12> Reinterprets;
2985ffd83dbSDimitry Andric 
2995ffd83dbSDimitry Andric   RecordKeeper &Records;
3005ffd83dbSDimitry Andric   llvm::StringMap<uint64_t> EltTypes;
3015ffd83dbSDimitry Andric   llvm::StringMap<uint64_t> MemEltTypes;
3025ffd83dbSDimitry Andric   llvm::StringMap<uint64_t> FlagTypes;
3035ffd83dbSDimitry Andric   llvm::StringMap<uint64_t> MergeTypes;
3045ffd83dbSDimitry Andric   llvm::StringMap<uint64_t> ImmCheckTypes;
3055ffd83dbSDimitry Andric 
3065ffd83dbSDimitry Andric public:
3075ffd83dbSDimitry Andric   SVEEmitter(RecordKeeper &R) : Records(R) {
3085ffd83dbSDimitry Andric     for (auto *RV : Records.getAllDerivedDefinitions("EltType"))
3095ffd83dbSDimitry Andric       EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
3105ffd83dbSDimitry Andric     for (auto *RV : Records.getAllDerivedDefinitions("MemEltType"))
3115ffd83dbSDimitry Andric       MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
3125ffd83dbSDimitry Andric     for (auto *RV : Records.getAllDerivedDefinitions("FlagType"))
3135ffd83dbSDimitry Andric       FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
3145ffd83dbSDimitry Andric     for (auto *RV : Records.getAllDerivedDefinitions("MergeType"))
3155ffd83dbSDimitry Andric       MergeTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
3165ffd83dbSDimitry Andric     for (auto *RV : Records.getAllDerivedDefinitions("ImmCheckType"))
3175ffd83dbSDimitry Andric       ImmCheckTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
3185ffd83dbSDimitry Andric   }
3195ffd83dbSDimitry Andric 
3205ffd83dbSDimitry Andric   /// Returns the enum value for the immcheck type
3215ffd83dbSDimitry Andric   unsigned getEnumValueForImmCheck(StringRef C) const {
3225ffd83dbSDimitry Andric     auto It = ImmCheckTypes.find(C);
3235ffd83dbSDimitry Andric     if (It != ImmCheckTypes.end())
3245ffd83dbSDimitry Andric       return It->getValue();
3255ffd83dbSDimitry Andric     llvm_unreachable("Unsupported imm check");
3265ffd83dbSDimitry Andric   }
3275ffd83dbSDimitry Andric 
3285ffd83dbSDimitry Andric   /// Returns the enum value for the flag type
3295ffd83dbSDimitry Andric   uint64_t getEnumValueForFlag(StringRef C) const {
3305ffd83dbSDimitry Andric     auto Res = FlagTypes.find(C);
3315ffd83dbSDimitry Andric     if (Res != FlagTypes.end())
3325ffd83dbSDimitry Andric       return Res->getValue();
3335ffd83dbSDimitry Andric     llvm_unreachable("Unsupported flag");
3345ffd83dbSDimitry Andric   }
3355ffd83dbSDimitry Andric 
3365ffd83dbSDimitry Andric   // Returns the SVETypeFlags for a given value and mask.
3375ffd83dbSDimitry Andric   uint64_t encodeFlag(uint64_t V, StringRef MaskName) const {
3385ffd83dbSDimitry Andric     auto It = FlagTypes.find(MaskName);
3395ffd83dbSDimitry Andric     if (It != FlagTypes.end()) {
3405ffd83dbSDimitry Andric       uint64_t Mask = It->getValue();
34106c3fb27SDimitry Andric       unsigned Shift = llvm::countr_zero(Mask);
34206c3fb27SDimitry Andric       assert(Shift < 64 && "Mask value produced an invalid shift value");
3435ffd83dbSDimitry Andric       return (V << Shift) & Mask;
3445ffd83dbSDimitry Andric     }
3455ffd83dbSDimitry Andric     llvm_unreachable("Unsupported flag");
3465ffd83dbSDimitry Andric   }
3475ffd83dbSDimitry Andric 
3485ffd83dbSDimitry Andric   // Returns the SVETypeFlags for the given element type.
3495ffd83dbSDimitry Andric   uint64_t encodeEltType(StringRef EltName) {
3505ffd83dbSDimitry Andric     auto It = EltTypes.find(EltName);
3515ffd83dbSDimitry Andric     if (It != EltTypes.end())
3525ffd83dbSDimitry Andric       return encodeFlag(It->getValue(), "EltTypeMask");
3535ffd83dbSDimitry Andric     llvm_unreachable("Unsupported EltType");
3545ffd83dbSDimitry Andric   }
3555ffd83dbSDimitry Andric 
3565ffd83dbSDimitry Andric   // Returns the SVETypeFlags for the given memory element type.
3575ffd83dbSDimitry Andric   uint64_t encodeMemoryElementType(uint64_t MT) {
3585ffd83dbSDimitry Andric     return encodeFlag(MT, "MemEltTypeMask");
3595ffd83dbSDimitry Andric   }
3605ffd83dbSDimitry Andric 
3615ffd83dbSDimitry Andric   // Returns the SVETypeFlags for the given merge type.
3625ffd83dbSDimitry Andric   uint64_t encodeMergeType(uint64_t MT) {
3635ffd83dbSDimitry Andric     return encodeFlag(MT, "MergeTypeMask");
3645ffd83dbSDimitry Andric   }
3655ffd83dbSDimitry Andric 
3665ffd83dbSDimitry Andric   // Returns the SVETypeFlags for the given splat operand.
3675ffd83dbSDimitry Andric   unsigned encodeSplatOperand(unsigned SplatIdx) {
3685ffd83dbSDimitry Andric     assert(SplatIdx < 7 && "SplatIdx out of encodable range");
3695ffd83dbSDimitry Andric     return encodeFlag(SplatIdx + 1, "SplatOperandMask");
3705ffd83dbSDimitry Andric   }
3715ffd83dbSDimitry Andric 
3725ffd83dbSDimitry Andric   // Returns the SVETypeFlags value for the given SVEType.
3735ffd83dbSDimitry Andric   uint64_t encodeTypeFlags(const SVEType &T);
3745ffd83dbSDimitry Andric 
3755ffd83dbSDimitry Andric   /// Emit arm_sve.h.
3765ffd83dbSDimitry Andric   void createHeader(raw_ostream &o);
3775ffd83dbSDimitry Andric 
3785f757f3fSDimitry Andric   // Emits core intrinsics in both arm_sme.h and arm_sve.h
3795f757f3fSDimitry Andric   void createCoreHeaderIntrinsics(raw_ostream &o, SVEEmitter &Emitter,
3805f757f3fSDimitry Andric                                   ACLEKind Kind);
3815f757f3fSDimitry Andric 
3825ffd83dbSDimitry Andric   /// Emit all the __builtin prototypes and code needed by Sema.
3835ffd83dbSDimitry Andric   void createBuiltins(raw_ostream &o);
3845ffd83dbSDimitry Andric 
3855ffd83dbSDimitry Andric   /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
3865ffd83dbSDimitry Andric   void createCodeGenMap(raw_ostream &o);
3875ffd83dbSDimitry Andric 
3885ffd83dbSDimitry Andric   /// Emit all the range checks for the immediates.
3895ffd83dbSDimitry Andric   void createRangeChecks(raw_ostream &o);
3905ffd83dbSDimitry Andric 
3915ffd83dbSDimitry Andric   /// Create the SVETypeFlags used in CGBuiltins
3925ffd83dbSDimitry Andric   void createTypeFlags(raw_ostream &o);
3935ffd83dbSDimitry Andric 
39406c3fb27SDimitry Andric   /// Emit arm_sme.h.
39506c3fb27SDimitry Andric   void createSMEHeader(raw_ostream &o);
39606c3fb27SDimitry Andric 
39706c3fb27SDimitry Andric   /// Emit all the SME __builtin prototypes and code needed by Sema.
39806c3fb27SDimitry Andric   void createSMEBuiltins(raw_ostream &o);
39906c3fb27SDimitry Andric 
40006c3fb27SDimitry Andric   /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
40106c3fb27SDimitry Andric   void createSMECodeGenMap(raw_ostream &o);
40206c3fb27SDimitry Andric 
403cb14a3feSDimitry Andric   /// Create a table for a builtin's requirement for PSTATE.SM.
404cb14a3feSDimitry Andric   void createStreamingAttrs(raw_ostream &o, ACLEKind Kind);
405cb14a3feSDimitry Andric 
40606c3fb27SDimitry Andric   /// Emit all the range checks for the immediates.
40706c3fb27SDimitry Andric   void createSMERangeChecks(raw_ostream &o);
40806c3fb27SDimitry Andric 
409cb14a3feSDimitry Andric   /// Create a table for a builtin's requirement for PSTATE.ZA.
410cb14a3feSDimitry Andric   void createBuiltinZAState(raw_ostream &OS);
411cb14a3feSDimitry Andric 
4125ffd83dbSDimitry Andric   /// Create intrinsic and add it to \p Out
41306c3fb27SDimitry Andric   void createIntrinsic(Record *R,
41406c3fb27SDimitry Andric                        SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out);
4155ffd83dbSDimitry Andric };
4165ffd83dbSDimitry Andric 
4175f757f3fSDimitry Andric const std::array<SVEEmitter::ReinterpretTypeInfo, 12> SVEEmitter::Reinterprets =
4185f757f3fSDimitry Andric     {{{SVEType("c", 'd'), "s8"},
4195f757f3fSDimitry Andric       {SVEType("Uc", 'd'), "u8"},
4205f757f3fSDimitry Andric       {SVEType("s", 'd'), "s16"},
4215f757f3fSDimitry Andric       {SVEType("Us", 'd'), "u16"},
4225f757f3fSDimitry Andric       {SVEType("i", 'd'), "s32"},
4235f757f3fSDimitry Andric       {SVEType("Ui", 'd'), "u32"},
4245f757f3fSDimitry Andric       {SVEType("l", 'd'), "s64"},
4255f757f3fSDimitry Andric       {SVEType("Ul", 'd'), "u64"},
4265f757f3fSDimitry Andric       {SVEType("h", 'd'), "f16"},
4275f757f3fSDimitry Andric       {SVEType("b", 'd'), "bf16"},
4285f757f3fSDimitry Andric       {SVEType("f", 'd'), "f32"},
4295f757f3fSDimitry Andric       {SVEType("d", 'd'), "f64"}}};
4305f757f3fSDimitry Andric 
4315ffd83dbSDimitry Andric } // end anonymous namespace
4325ffd83dbSDimitry Andric 
4335ffd83dbSDimitry Andric 
4345ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
4355ffd83dbSDimitry Andric // Type implementation
4365ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
4375ffd83dbSDimitry Andric 
4385ffd83dbSDimitry Andric std::string SVEType::builtin_str() const {
4395ffd83dbSDimitry Andric   std::string S;
4405ffd83dbSDimitry Andric   if (isVoid())
4415ffd83dbSDimitry Andric     return "v";
4425ffd83dbSDimitry Andric 
443fe6060f1SDimitry Andric   if (isScalarPredicate())
444fe6060f1SDimitry Andric     return "b";
445fe6060f1SDimitry Andric 
44606c3fb27SDimitry Andric   if (isSvcount())
44706c3fb27SDimitry Andric     return "Qa";
44806c3fb27SDimitry Andric 
4495ffd83dbSDimitry Andric   if (isVoidPointer())
4505ffd83dbSDimitry Andric     S += "v";
4515ffd83dbSDimitry Andric   else if (!isFloatingPoint())
4525ffd83dbSDimitry Andric     switch (ElementBitwidth) {
4535ffd83dbSDimitry Andric     case 1: S += "b"; break;
4545ffd83dbSDimitry Andric     case 8: S += "c"; break;
4555ffd83dbSDimitry Andric     case 16: S += "s"; break;
4565ffd83dbSDimitry Andric     case 32: S += "i"; break;
4575ffd83dbSDimitry Andric     case 64: S += "Wi"; break;
4585ffd83dbSDimitry Andric     case 128: S += "LLLi"; break;
4595ffd83dbSDimitry Andric     default: llvm_unreachable("Unhandled case!");
4605ffd83dbSDimitry Andric     }
4615ffd83dbSDimitry Andric   else if (isFloat())
4625ffd83dbSDimitry Andric     switch (ElementBitwidth) {
4635ffd83dbSDimitry Andric     case 16: S += "h"; break;
4645ffd83dbSDimitry Andric     case 32: S += "f"; break;
4655ffd83dbSDimitry Andric     case 64: S += "d"; break;
4665ffd83dbSDimitry Andric     default: llvm_unreachable("Unhandled case!");
4675ffd83dbSDimitry Andric     }
4685ffd83dbSDimitry Andric   else if (isBFloat()) {
4695ffd83dbSDimitry Andric     assert(ElementBitwidth == 16 && "Not a valid BFloat.");
4705ffd83dbSDimitry Andric     S += "y";
4715ffd83dbSDimitry Andric   }
4725ffd83dbSDimitry Andric 
4735ffd83dbSDimitry Andric   if (!isFloatingPoint()) {
4745ffd83dbSDimitry Andric     if ((isChar() || isPointer()) && !isVoidPointer()) {
4755ffd83dbSDimitry Andric       // Make chars and typed pointers explicitly signed.
4765ffd83dbSDimitry Andric       if (Signed)
4775ffd83dbSDimitry Andric         S = "S" + S;
4785ffd83dbSDimitry Andric       else if (!Signed)
4795ffd83dbSDimitry Andric         S = "U" + S;
4805ffd83dbSDimitry Andric     } else if (!isVoidPointer() && !Signed) {
4815ffd83dbSDimitry Andric       S = "U" + S;
4825ffd83dbSDimitry Andric     }
4835ffd83dbSDimitry Andric   }
4845ffd83dbSDimitry Andric 
4855ffd83dbSDimitry Andric   // Constant indices are "int", but have the "constant expression" modifier.
4865ffd83dbSDimitry Andric   if (isImmediate()) {
4875ffd83dbSDimitry Andric     assert(!isFloat() && "fp immediates are not supported");
4885ffd83dbSDimitry Andric     S = "I" + S;
4895ffd83dbSDimitry Andric   }
4905ffd83dbSDimitry Andric 
4915ffd83dbSDimitry Andric   if (isScalar()) {
4925ffd83dbSDimitry Andric     if (Constant) S += "C";
4935ffd83dbSDimitry Andric     if (Pointer) S += "*";
4945ffd83dbSDimitry Andric     return S;
4955ffd83dbSDimitry Andric   }
4965ffd83dbSDimitry Andric 
4975f757f3fSDimitry Andric   if (isFixedLengthVector())
4985f757f3fSDimitry Andric     return "V" + utostr(getNumElements() * NumVectors) + S;
4995ffd83dbSDimitry Andric   return "q" + utostr(getNumElements() * NumVectors) + S;
5005ffd83dbSDimitry Andric }
5015ffd83dbSDimitry Andric 
5025ffd83dbSDimitry Andric std::string SVEType::str() const {
5035ffd83dbSDimitry Andric   if (isPredicatePattern())
504e8d8bef9SDimitry Andric     return "enum svpattern";
5055ffd83dbSDimitry Andric 
5065ffd83dbSDimitry Andric   if (isPrefetchOp())
507e8d8bef9SDimitry Andric     return "enum svprfop";
5085ffd83dbSDimitry Andric 
5095ffd83dbSDimitry Andric   std::string S;
5105ffd83dbSDimitry Andric   if (Void)
5115ffd83dbSDimitry Andric     S += "void";
5125ffd83dbSDimitry Andric   else {
51306c3fb27SDimitry Andric     if (isScalableVector() || isSvcount())
5145ffd83dbSDimitry Andric       S += "sv";
5155ffd83dbSDimitry Andric     if (!Signed && !isFloatingPoint())
5165ffd83dbSDimitry Andric       S += "u";
5175ffd83dbSDimitry Andric 
5185ffd83dbSDimitry Andric     if (Float)
5195ffd83dbSDimitry Andric       S += "float";
52006c3fb27SDimitry Andric     else if (isSvcount())
52106c3fb27SDimitry Andric       S += "count";
5225ffd83dbSDimitry Andric     else if (isScalarPredicate() || isPredicateVector())
5235ffd83dbSDimitry Andric       S += "bool";
5245ffd83dbSDimitry Andric     else if (isBFloat())
5255ffd83dbSDimitry Andric       S += "bfloat";
5265ffd83dbSDimitry Andric     else
5275ffd83dbSDimitry Andric       S += "int";
5285ffd83dbSDimitry Andric 
52906c3fb27SDimitry Andric     if (!isScalarPredicate() && !isPredicateVector() && !isSvcount())
5305ffd83dbSDimitry Andric       S += utostr(ElementBitwidth);
5315f757f3fSDimitry Andric     if (isFixedLengthVector())
5325ffd83dbSDimitry Andric       S += "x" + utostr(getNumElements());
5335ffd83dbSDimitry Andric     if (NumVectors > 1)
5345ffd83dbSDimitry Andric       S += "x" + utostr(NumVectors);
5355ffd83dbSDimitry Andric     if (!isScalarPredicate())
5365ffd83dbSDimitry Andric       S += "_t";
5375ffd83dbSDimitry Andric   }
5385ffd83dbSDimitry Andric 
5395ffd83dbSDimitry Andric   if (Constant)
5405ffd83dbSDimitry Andric     S += " const";
5415ffd83dbSDimitry Andric   if (Pointer)
5425ffd83dbSDimitry Andric     S += " *";
5435ffd83dbSDimitry Andric 
5445ffd83dbSDimitry Andric   return S;
5455ffd83dbSDimitry Andric }
5465f757f3fSDimitry Andric 
5475f757f3fSDimitry Andric void SVEType::applyTypespec(StringRef TS) {
5485ffd83dbSDimitry Andric   for (char I : TS) {
5495ffd83dbSDimitry Andric     switch (I) {
55006c3fb27SDimitry Andric     case 'Q':
55106c3fb27SDimitry Andric       Svcount = true;
55206c3fb27SDimitry Andric       break;
5535ffd83dbSDimitry Andric     case 'P':
5545ffd83dbSDimitry Andric       Predicate = true;
5555ffd83dbSDimitry Andric       break;
5565ffd83dbSDimitry Andric     case 'U':
5575ffd83dbSDimitry Andric       Signed = false;
5585ffd83dbSDimitry Andric       break;
5595ffd83dbSDimitry Andric     case 'c':
5605ffd83dbSDimitry Andric       ElementBitwidth = 8;
5615ffd83dbSDimitry Andric       break;
5625ffd83dbSDimitry Andric     case 's':
5635ffd83dbSDimitry Andric       ElementBitwidth = 16;
5645ffd83dbSDimitry Andric       break;
5655ffd83dbSDimitry Andric     case 'i':
5665ffd83dbSDimitry Andric       ElementBitwidth = 32;
5675ffd83dbSDimitry Andric       break;
5685ffd83dbSDimitry Andric     case 'l':
5695ffd83dbSDimitry Andric       ElementBitwidth = 64;
5705ffd83dbSDimitry Andric       break;
57106c3fb27SDimitry Andric     case 'q':
57206c3fb27SDimitry Andric       ElementBitwidth = 128;
57306c3fb27SDimitry Andric       break;
5745ffd83dbSDimitry Andric     case 'h':
5755ffd83dbSDimitry Andric       Float = true;
5765ffd83dbSDimitry Andric       ElementBitwidth = 16;
5775ffd83dbSDimitry Andric       break;
5785ffd83dbSDimitry Andric     case 'f':
5795ffd83dbSDimitry Andric       Float = true;
5805ffd83dbSDimitry Andric       ElementBitwidth = 32;
5815ffd83dbSDimitry Andric       break;
5825ffd83dbSDimitry Andric     case 'd':
5835ffd83dbSDimitry Andric       Float = true;
5845ffd83dbSDimitry Andric       ElementBitwidth = 64;
5855ffd83dbSDimitry Andric       break;
5865ffd83dbSDimitry Andric     case 'b':
5875ffd83dbSDimitry Andric       BFloat = true;
5885ffd83dbSDimitry Andric       Float = false;
5895ffd83dbSDimitry Andric       ElementBitwidth = 16;
5905ffd83dbSDimitry Andric       break;
5915ffd83dbSDimitry Andric     default:
5925ffd83dbSDimitry Andric       llvm_unreachable("Unhandled type code!");
5935ffd83dbSDimitry Andric     }
5945ffd83dbSDimitry Andric   }
5955ffd83dbSDimitry Andric   assert(ElementBitwidth != ~0U && "Bad element bitwidth!");
5965ffd83dbSDimitry Andric }
5975ffd83dbSDimitry Andric 
5985ffd83dbSDimitry Andric void SVEType::applyModifier(char Mod) {
5995ffd83dbSDimitry Andric   switch (Mod) {
6005ffd83dbSDimitry Andric   case 'v':
6015ffd83dbSDimitry Andric     Void = true;
6025ffd83dbSDimitry Andric     break;
6035ffd83dbSDimitry Andric   case 'd':
6045ffd83dbSDimitry Andric     DefaultType = true;
6055ffd83dbSDimitry Andric     break;
6065ffd83dbSDimitry Andric   case 'c':
6075ffd83dbSDimitry Andric     Constant = true;
608bdd1243dSDimitry Andric     [[fallthrough]];
6095ffd83dbSDimitry Andric   case 'p':
6105ffd83dbSDimitry Andric     Pointer = true;
6115ffd83dbSDimitry Andric     Bitwidth = ElementBitwidth;
6125ffd83dbSDimitry Andric     NumVectors = 0;
6135ffd83dbSDimitry Andric     break;
6145ffd83dbSDimitry Andric   case 'e':
6155ffd83dbSDimitry Andric     Signed = false;
6165ffd83dbSDimitry Andric     ElementBitwidth /= 2;
6175ffd83dbSDimitry Andric     break;
6185ffd83dbSDimitry Andric   case 'h':
6195ffd83dbSDimitry Andric     ElementBitwidth /= 2;
6205ffd83dbSDimitry Andric     break;
6215ffd83dbSDimitry Andric   case 'q':
6225ffd83dbSDimitry Andric     ElementBitwidth /= 4;
6235ffd83dbSDimitry Andric     break;
6245ffd83dbSDimitry Andric   case 'b':
6255ffd83dbSDimitry Andric     Signed = false;
6265ffd83dbSDimitry Andric     Float = false;
6275ffd83dbSDimitry Andric     BFloat = false;
6285ffd83dbSDimitry Andric     ElementBitwidth /= 4;
6295ffd83dbSDimitry Andric     break;
6305ffd83dbSDimitry Andric   case 'o':
6315ffd83dbSDimitry Andric     ElementBitwidth *= 4;
6325ffd83dbSDimitry Andric     break;
6335ffd83dbSDimitry Andric   case 'P':
6345ffd83dbSDimitry Andric     Signed = true;
6355ffd83dbSDimitry Andric     Float = false;
6365ffd83dbSDimitry Andric     BFloat = false;
6375ffd83dbSDimitry Andric     Predicate = true;
63806c3fb27SDimitry Andric     Svcount = false;
6395ffd83dbSDimitry Andric     Bitwidth = 16;
6405ffd83dbSDimitry Andric     ElementBitwidth = 1;
6415ffd83dbSDimitry Andric     break;
6425f757f3fSDimitry Andric   case '{':
6435f757f3fSDimitry Andric     IsScalable = false;
6445f757f3fSDimitry Andric     Bitwidth = 128;
6455f757f3fSDimitry Andric     NumVectors = 1;
6465f757f3fSDimitry Andric     break;
6475ffd83dbSDimitry Andric   case 's':
6485ffd83dbSDimitry Andric   case 'a':
6495ffd83dbSDimitry Andric     Bitwidth = ElementBitwidth;
6505ffd83dbSDimitry Andric     NumVectors = 0;
6515ffd83dbSDimitry Andric     break;
6525ffd83dbSDimitry Andric   case 'R':
6535ffd83dbSDimitry Andric     ElementBitwidth /= 2;
6545ffd83dbSDimitry Andric     NumVectors = 0;
6555ffd83dbSDimitry Andric     break;
6565ffd83dbSDimitry Andric   case 'r':
6575ffd83dbSDimitry Andric     ElementBitwidth /= 4;
6585ffd83dbSDimitry Andric     NumVectors = 0;
6595ffd83dbSDimitry Andric     break;
6605ffd83dbSDimitry Andric   case '@':
6615ffd83dbSDimitry Andric     Signed = false;
6625ffd83dbSDimitry Andric     Float = false;
6635ffd83dbSDimitry Andric     BFloat = false;
6645ffd83dbSDimitry Andric     ElementBitwidth /= 4;
6655ffd83dbSDimitry Andric     NumVectors = 0;
6665ffd83dbSDimitry Andric     break;
6675ffd83dbSDimitry Andric   case 'K':
6685ffd83dbSDimitry Andric     Signed = true;
6695ffd83dbSDimitry Andric     Float = false;
6705ffd83dbSDimitry Andric     BFloat = false;
6715ffd83dbSDimitry Andric     Bitwidth = ElementBitwidth;
6725ffd83dbSDimitry Andric     NumVectors = 0;
6735ffd83dbSDimitry Andric     break;
6745ffd83dbSDimitry Andric   case 'L':
6755ffd83dbSDimitry Andric     Signed = false;
6765ffd83dbSDimitry Andric     Float = false;
6775ffd83dbSDimitry Andric     BFloat = false;
6785ffd83dbSDimitry Andric     Bitwidth = ElementBitwidth;
6795ffd83dbSDimitry Andric     NumVectors = 0;
6805ffd83dbSDimitry Andric     break;
6815ffd83dbSDimitry Andric   case 'u':
6825ffd83dbSDimitry Andric     Predicate = false;
68306c3fb27SDimitry Andric     Svcount = false;
6845ffd83dbSDimitry Andric     Signed = false;
6855ffd83dbSDimitry Andric     Float = false;
6865ffd83dbSDimitry Andric     BFloat = false;
6875ffd83dbSDimitry Andric     break;
6885ffd83dbSDimitry Andric   case 'x':
6895ffd83dbSDimitry Andric     Predicate = false;
69006c3fb27SDimitry Andric     Svcount = false;
6915ffd83dbSDimitry Andric     Signed = true;
6925ffd83dbSDimitry Andric     Float = false;
6935ffd83dbSDimitry Andric     BFloat = false;
6945ffd83dbSDimitry Andric     break;
6955ffd83dbSDimitry Andric   case 'i':
6965ffd83dbSDimitry Andric     Predicate = false;
69706c3fb27SDimitry Andric     Svcount = false;
6985ffd83dbSDimitry Andric     Float = false;
6995ffd83dbSDimitry Andric     BFloat = false;
7005ffd83dbSDimitry Andric     ElementBitwidth = Bitwidth = 64;
7015ffd83dbSDimitry Andric     NumVectors = 0;
7025ffd83dbSDimitry Andric     Signed = false;
7035ffd83dbSDimitry Andric     Immediate = true;
7045ffd83dbSDimitry Andric     break;
7055ffd83dbSDimitry Andric   case 'I':
7065ffd83dbSDimitry Andric     Predicate = false;
70706c3fb27SDimitry Andric     Svcount = false;
7085ffd83dbSDimitry Andric     Float = false;
7095ffd83dbSDimitry Andric     BFloat = false;
7105ffd83dbSDimitry Andric     ElementBitwidth = Bitwidth = 32;
7115ffd83dbSDimitry Andric     NumVectors = 0;
7125ffd83dbSDimitry Andric     Signed = true;
7135ffd83dbSDimitry Andric     Immediate = true;
7145ffd83dbSDimitry Andric     PredicatePattern = true;
7155ffd83dbSDimitry Andric     break;
7165ffd83dbSDimitry Andric   case 'J':
7175ffd83dbSDimitry Andric     Predicate = false;
71806c3fb27SDimitry Andric     Svcount = false;
7195ffd83dbSDimitry Andric     Float = false;
7205ffd83dbSDimitry Andric     BFloat = false;
7215ffd83dbSDimitry Andric     ElementBitwidth = Bitwidth = 32;
7225ffd83dbSDimitry Andric     NumVectors = 0;
7235ffd83dbSDimitry Andric     Signed = true;
7245ffd83dbSDimitry Andric     Immediate = true;
7255ffd83dbSDimitry Andric     PrefetchOp = true;
7265ffd83dbSDimitry Andric     break;
7275ffd83dbSDimitry Andric   case 'k':
7285ffd83dbSDimitry Andric     Predicate = false;
72906c3fb27SDimitry Andric     Svcount = false;
7305ffd83dbSDimitry Andric     Signed = true;
7315ffd83dbSDimitry Andric     Float = false;
7325ffd83dbSDimitry Andric     BFloat = false;
7335ffd83dbSDimitry Andric     ElementBitwidth = Bitwidth = 32;
7345ffd83dbSDimitry Andric     NumVectors = 0;
7355ffd83dbSDimitry Andric     break;
7365ffd83dbSDimitry Andric   case 'l':
7375ffd83dbSDimitry Andric     Predicate = false;
73806c3fb27SDimitry Andric     Svcount = false;
7395ffd83dbSDimitry Andric     Signed = true;
7405ffd83dbSDimitry Andric     Float = false;
7415ffd83dbSDimitry Andric     BFloat = false;
7425ffd83dbSDimitry Andric     ElementBitwidth = Bitwidth = 64;
7435ffd83dbSDimitry Andric     NumVectors = 0;
7445ffd83dbSDimitry Andric     break;
7455ffd83dbSDimitry Andric   case 'm':
7465ffd83dbSDimitry Andric     Predicate = false;
74706c3fb27SDimitry Andric     Svcount = false;
7485ffd83dbSDimitry Andric     Signed = false;
7495ffd83dbSDimitry Andric     Float = false;
7505ffd83dbSDimitry Andric     BFloat = false;
7515ffd83dbSDimitry Andric     ElementBitwidth = Bitwidth = 32;
7525ffd83dbSDimitry Andric     NumVectors = 0;
7535ffd83dbSDimitry Andric     break;
7545ffd83dbSDimitry Andric   case 'n':
7555ffd83dbSDimitry Andric     Predicate = false;
75606c3fb27SDimitry Andric     Svcount = false;
7575ffd83dbSDimitry Andric     Signed = false;
7585ffd83dbSDimitry Andric     Float = false;
7595ffd83dbSDimitry Andric     BFloat = false;
7605ffd83dbSDimitry Andric     ElementBitwidth = Bitwidth = 64;
7615ffd83dbSDimitry Andric     NumVectors = 0;
7625ffd83dbSDimitry Andric     break;
7635ffd83dbSDimitry Andric   case 'w':
7645ffd83dbSDimitry Andric     ElementBitwidth = 64;
7655ffd83dbSDimitry Andric     break;
7665ffd83dbSDimitry Andric   case 'j':
7675ffd83dbSDimitry Andric     ElementBitwidth = Bitwidth = 64;
7685ffd83dbSDimitry Andric     NumVectors = 0;
7695ffd83dbSDimitry Andric     break;
7705ffd83dbSDimitry Andric   case 'f':
7715ffd83dbSDimitry Andric     Signed = false;
7725ffd83dbSDimitry Andric     ElementBitwidth = Bitwidth = 64;
7735ffd83dbSDimitry Andric     NumVectors = 0;
7745ffd83dbSDimitry Andric     break;
7755ffd83dbSDimitry Andric   case 'g':
7765ffd83dbSDimitry Andric     Signed = false;
7775ffd83dbSDimitry Andric     Float = false;
7785ffd83dbSDimitry Andric     BFloat = false;
7795ffd83dbSDimitry Andric     ElementBitwidth = 64;
7805ffd83dbSDimitry Andric     break;
7815f757f3fSDimitry Andric   case '[':
7825f757f3fSDimitry Andric     Signed = false;
7835f757f3fSDimitry Andric     Float = false;
7845f757f3fSDimitry Andric     BFloat = false;
7855f757f3fSDimitry Andric     ElementBitwidth = 8;
7865f757f3fSDimitry Andric     break;
7875ffd83dbSDimitry Andric   case 't':
7885ffd83dbSDimitry Andric     Signed = true;
7895ffd83dbSDimitry Andric     Float = false;
7905ffd83dbSDimitry Andric     BFloat = false;
7915ffd83dbSDimitry Andric     ElementBitwidth = 32;
7925ffd83dbSDimitry Andric     break;
7935ffd83dbSDimitry Andric   case 'z':
7945ffd83dbSDimitry Andric     Signed = false;
7955ffd83dbSDimitry Andric     Float = false;
7965ffd83dbSDimitry Andric     BFloat = false;
7975ffd83dbSDimitry Andric     ElementBitwidth = 32;
7985ffd83dbSDimitry Andric     break;
7995ffd83dbSDimitry Andric   case 'O':
8005ffd83dbSDimitry Andric     Predicate = false;
80106c3fb27SDimitry Andric     Svcount = false;
8025ffd83dbSDimitry Andric     Float = true;
8035ffd83dbSDimitry Andric     ElementBitwidth = 16;
8045ffd83dbSDimitry Andric     break;
8055ffd83dbSDimitry Andric   case 'M':
8065ffd83dbSDimitry Andric     Predicate = false;
80706c3fb27SDimitry Andric     Svcount = false;
8085ffd83dbSDimitry Andric     Float = true;
8095ffd83dbSDimitry Andric     BFloat = false;
8105ffd83dbSDimitry Andric     ElementBitwidth = 32;
8115ffd83dbSDimitry Andric     break;
8125ffd83dbSDimitry Andric   case 'N':
8135ffd83dbSDimitry Andric     Predicate = false;
81406c3fb27SDimitry Andric     Svcount = false;
8155ffd83dbSDimitry Andric     Float = true;
8165ffd83dbSDimitry Andric     ElementBitwidth = 64;
8175ffd83dbSDimitry Andric     break;
8185ffd83dbSDimitry Andric   case 'Q':
8195ffd83dbSDimitry Andric     Constant = true;
8205ffd83dbSDimitry Andric     Pointer = true;
8215ffd83dbSDimitry Andric     Void = true;
8225ffd83dbSDimitry Andric     NumVectors = 0;
8235ffd83dbSDimitry Andric     break;
8245ffd83dbSDimitry Andric   case 'S':
8255ffd83dbSDimitry Andric     Constant = true;
8265ffd83dbSDimitry Andric     Pointer = true;
8275ffd83dbSDimitry Andric     ElementBitwidth = Bitwidth = 8;
8285ffd83dbSDimitry Andric     NumVectors = 0;
8295ffd83dbSDimitry Andric     Signed = true;
8305ffd83dbSDimitry Andric     break;
8315ffd83dbSDimitry Andric   case 'W':
8325ffd83dbSDimitry Andric     Constant = true;
8335ffd83dbSDimitry Andric     Pointer = true;
8345ffd83dbSDimitry Andric     ElementBitwidth = Bitwidth = 8;
8355ffd83dbSDimitry Andric     NumVectors = 0;
8365ffd83dbSDimitry Andric     Signed = false;
8375ffd83dbSDimitry Andric     break;
8385ffd83dbSDimitry Andric   case 'T':
8395ffd83dbSDimitry Andric     Constant = true;
8405ffd83dbSDimitry Andric     Pointer = true;
8415ffd83dbSDimitry Andric     ElementBitwidth = Bitwidth = 16;
8425ffd83dbSDimitry Andric     NumVectors = 0;
8435ffd83dbSDimitry Andric     Signed = true;
8445ffd83dbSDimitry Andric     break;
8455ffd83dbSDimitry Andric   case 'X':
8465ffd83dbSDimitry Andric     Constant = true;
8475ffd83dbSDimitry Andric     Pointer = true;
8485ffd83dbSDimitry Andric     ElementBitwidth = Bitwidth = 16;
8495ffd83dbSDimitry Andric     NumVectors = 0;
8505ffd83dbSDimitry Andric     Signed = false;
8515ffd83dbSDimitry Andric     break;
8525ffd83dbSDimitry Andric   case 'Y':
8535ffd83dbSDimitry Andric     Constant = true;
8545ffd83dbSDimitry Andric     Pointer = true;
8555ffd83dbSDimitry Andric     ElementBitwidth = Bitwidth = 32;
8565ffd83dbSDimitry Andric     NumVectors = 0;
8575ffd83dbSDimitry Andric     Signed = false;
8585ffd83dbSDimitry Andric     break;
8595ffd83dbSDimitry Andric   case 'U':
8605ffd83dbSDimitry Andric     Constant = true;
8615ffd83dbSDimitry Andric     Pointer = true;
8625ffd83dbSDimitry Andric     ElementBitwidth = Bitwidth = 32;
8635ffd83dbSDimitry Andric     NumVectors = 0;
8645ffd83dbSDimitry Andric     Signed = true;
8655ffd83dbSDimitry Andric     break;
86606c3fb27SDimitry Andric   case '%':
86706c3fb27SDimitry Andric     Pointer = true;
86806c3fb27SDimitry Andric     Void = true;
86906c3fb27SDimitry Andric     NumVectors = 0;
87006c3fb27SDimitry Andric     break;
8715ffd83dbSDimitry Andric   case 'A':
8725ffd83dbSDimitry Andric     Pointer = true;
8735ffd83dbSDimitry Andric     ElementBitwidth = Bitwidth = 8;
8745ffd83dbSDimitry Andric     NumVectors = 0;
8755ffd83dbSDimitry Andric     Signed = true;
8765ffd83dbSDimitry Andric     break;
8775ffd83dbSDimitry Andric   case 'B':
8785ffd83dbSDimitry Andric     Pointer = true;
8795ffd83dbSDimitry Andric     ElementBitwidth = Bitwidth = 16;
8805ffd83dbSDimitry Andric     NumVectors = 0;
8815ffd83dbSDimitry Andric     Signed = true;
8825ffd83dbSDimitry Andric     break;
8835ffd83dbSDimitry Andric   case 'C':
8845ffd83dbSDimitry Andric     Pointer = true;
8855ffd83dbSDimitry Andric     ElementBitwidth = Bitwidth = 32;
8865ffd83dbSDimitry Andric     NumVectors = 0;
8875ffd83dbSDimitry Andric     Signed = true;
8885ffd83dbSDimitry Andric     break;
8895ffd83dbSDimitry Andric   case 'D':
8905ffd83dbSDimitry Andric     Pointer = true;
8915ffd83dbSDimitry Andric     ElementBitwidth = Bitwidth = 64;
8925ffd83dbSDimitry Andric     NumVectors = 0;
8935ffd83dbSDimitry Andric     Signed = true;
8945ffd83dbSDimitry Andric     break;
8955ffd83dbSDimitry Andric   case 'E':
8965ffd83dbSDimitry Andric     Pointer = true;
8975ffd83dbSDimitry Andric     ElementBitwidth = Bitwidth = 8;
8985ffd83dbSDimitry Andric     NumVectors = 0;
8995ffd83dbSDimitry Andric     Signed = false;
9005ffd83dbSDimitry Andric     break;
9015ffd83dbSDimitry Andric   case 'F':
9025ffd83dbSDimitry Andric     Pointer = true;
9035ffd83dbSDimitry Andric     ElementBitwidth = Bitwidth = 16;
9045ffd83dbSDimitry Andric     NumVectors = 0;
9055ffd83dbSDimitry Andric     Signed = false;
9065ffd83dbSDimitry Andric     break;
9075ffd83dbSDimitry Andric   case 'G':
9085ffd83dbSDimitry Andric     Pointer = true;
9095ffd83dbSDimitry Andric     ElementBitwidth = Bitwidth = 32;
9105ffd83dbSDimitry Andric     NumVectors = 0;
9115ffd83dbSDimitry Andric     Signed = false;
9125ffd83dbSDimitry Andric     break;
9135f757f3fSDimitry Andric   case '$':
9145f757f3fSDimitry Andric     Predicate = false;
9155f757f3fSDimitry Andric     Svcount = false;
9165f757f3fSDimitry Andric     Float = false;
9175f757f3fSDimitry Andric     BFloat = true;
9185f757f3fSDimitry Andric     ElementBitwidth = 16;
9195f757f3fSDimitry Andric     break;
92006c3fb27SDimitry Andric   case '}':
92106c3fb27SDimitry Andric     Predicate = false;
92206c3fb27SDimitry Andric     Signed = true;
92306c3fb27SDimitry Andric     Svcount = true;
92406c3fb27SDimitry Andric     NumVectors = 0;
92506c3fb27SDimitry Andric     Float = false;
92606c3fb27SDimitry Andric     BFloat = false;
92706c3fb27SDimitry Andric     break;
9285f757f3fSDimitry Andric   case '.':
9295f757f3fSDimitry Andric     llvm_unreachable(". is never a type in itself");
9305f757f3fSDimitry Andric     break;
9315ffd83dbSDimitry Andric   default:
9325ffd83dbSDimitry Andric     llvm_unreachable("Unhandled character!");
9335ffd83dbSDimitry Andric   }
9345ffd83dbSDimitry Andric }
9355ffd83dbSDimitry Andric 
9365f757f3fSDimitry Andric /// Returns the modifier and number of vectors for the given operand \p Op.
9375f757f3fSDimitry Andric std::pair<char, unsigned> getProtoModifier(StringRef Proto, unsigned Op) {
9385f757f3fSDimitry Andric   for (unsigned P = 0; !Proto.empty(); ++P) {
9395f757f3fSDimitry Andric     unsigned NumVectors = 1;
9405f757f3fSDimitry Andric     unsigned CharsToSkip = 1;
9415f757f3fSDimitry Andric     char Mod = Proto[0];
9425f757f3fSDimitry Andric     if (Mod == '2' || Mod == '3' || Mod == '4') {
9435f757f3fSDimitry Andric       NumVectors = Mod - '0';
9445f757f3fSDimitry Andric       Mod = 'd';
9455f757f3fSDimitry Andric       if (Proto.size() > 1 && Proto[1] == '.') {
9465f757f3fSDimitry Andric         Mod = Proto[2];
9475f757f3fSDimitry Andric         CharsToSkip = 3;
9485f757f3fSDimitry Andric       }
9495f757f3fSDimitry Andric     }
9505f757f3fSDimitry Andric 
9515f757f3fSDimitry Andric     if (P == Op)
9525f757f3fSDimitry Andric       return {Mod, NumVectors};
9535f757f3fSDimitry Andric 
9545f757f3fSDimitry Andric     Proto = Proto.drop_front(CharsToSkip);
9555f757f3fSDimitry Andric   }
9565f757f3fSDimitry Andric   llvm_unreachable("Unexpected Op");
9575f757f3fSDimitry Andric }
9585ffd83dbSDimitry Andric 
9595ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
9605ffd83dbSDimitry Andric // Intrinsic implementation
9615ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
9625ffd83dbSDimitry Andric 
9635ffd83dbSDimitry Andric Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
9645ffd83dbSDimitry Andric                      StringRef MergeSuffix, uint64_t MemoryElementTy,
9655ffd83dbSDimitry Andric                      StringRef LLVMName, uint64_t Flags,
9665ffd83dbSDimitry Andric                      ArrayRef<ImmCheck> Checks, TypeSpec BT, ClassKind Class,
967*0fca6ea1SDimitry Andric                      SVEEmitter &Emitter, StringRef SVEGuard,
968*0fca6ea1SDimitry Andric                      StringRef SMEGuard)
9695ffd83dbSDimitry Andric     : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()),
970*0fca6ea1SDimitry Andric       BaseTypeSpec(BT), Class(Class), SVEGuard(SVEGuard.str()),
971*0fca6ea1SDimitry Andric       SMEGuard(SMEGuard.str()), MergeSuffix(MergeSuffix.str()),
972*0fca6ea1SDimitry Andric       BaseType(BT, 'd'), Flags(Flags), ImmChecks(Checks.begin(), Checks.end()) {
9735ffd83dbSDimitry Andric   // Types[0] is the return value.
9745f757f3fSDimitry Andric   for (unsigned I = 0; I < (getNumParams() + 1); ++I) {
9755f757f3fSDimitry Andric     char Mod;
9765f757f3fSDimitry Andric     unsigned NumVectors;
9775f757f3fSDimitry Andric     std::tie(Mod, NumVectors) = getProtoModifier(Proto, I);
9785f757f3fSDimitry Andric     SVEType T(BaseTypeSpec, Mod, NumVectors);
9795ffd83dbSDimitry Andric     Types.push_back(T);
9805ffd83dbSDimitry Andric 
9815ffd83dbSDimitry Andric     // Add range checks for immediates
9825ffd83dbSDimitry Andric     if (I > 0) {
9835ffd83dbSDimitry Andric       if (T.isPredicatePattern())
9845ffd83dbSDimitry Andric         ImmChecks.emplace_back(
9855ffd83dbSDimitry Andric             I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_31"));
9865ffd83dbSDimitry Andric       else if (T.isPrefetchOp())
9875ffd83dbSDimitry Andric         ImmChecks.emplace_back(
9885ffd83dbSDimitry Andric             I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_13"));
9895ffd83dbSDimitry Andric     }
9905ffd83dbSDimitry Andric   }
9915ffd83dbSDimitry Andric 
9925ffd83dbSDimitry Andric   // Set flags based on properties
9935ffd83dbSDimitry Andric   this->Flags |= Emitter.encodeTypeFlags(BaseType);
9945ffd83dbSDimitry Andric   this->Flags |= Emitter.encodeMemoryElementType(MemoryElementTy);
9955ffd83dbSDimitry Andric   this->Flags |= Emitter.encodeMergeType(MergeTy);
9965ffd83dbSDimitry Andric   if (hasSplat())
9975ffd83dbSDimitry Andric     this->Flags |= Emitter.encodeSplatOperand(getSplatIdx());
9985ffd83dbSDimitry Andric }
9995ffd83dbSDimitry Andric 
10005ffd83dbSDimitry Andric std::string Intrinsic::getBuiltinTypeStr() {
10015ffd83dbSDimitry Andric   std::string S = getReturnType().builtin_str();
10025ffd83dbSDimitry Andric   for (unsigned I = 0; I < getNumParams(); ++I)
10035ffd83dbSDimitry Andric     S += getParamType(I).builtin_str();
10045ffd83dbSDimitry Andric 
10055ffd83dbSDimitry Andric   return S;
10065ffd83dbSDimitry Andric }
10075ffd83dbSDimitry Andric 
10085ffd83dbSDimitry Andric std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS,
10095ffd83dbSDimitry Andric                                             std::string Proto) const {
10105ffd83dbSDimitry Andric   std::string Ret = Name;
10115ffd83dbSDimitry Andric   while (Ret.find('{') != std::string::npos) {
10125ffd83dbSDimitry Andric     size_t Pos = Ret.find('{');
10135ffd83dbSDimitry Andric     size_t End = Ret.find('}');
10145ffd83dbSDimitry Andric     unsigned NumChars = End - Pos + 1;
10155ffd83dbSDimitry Andric     assert(NumChars == 3 && "Unexpected template argument");
10165ffd83dbSDimitry Andric 
10175ffd83dbSDimitry Andric     SVEType T;
10185ffd83dbSDimitry Andric     char C = Ret[Pos+1];
10195ffd83dbSDimitry Andric     switch(C) {
10205ffd83dbSDimitry Andric     default:
10215ffd83dbSDimitry Andric       llvm_unreachable("Unknown predication specifier");
10225ffd83dbSDimitry Andric     case 'd':
10235ffd83dbSDimitry Andric       T = SVEType(TS, 'd');
10245ffd83dbSDimitry Andric       break;
10255ffd83dbSDimitry Andric     case '0':
10265ffd83dbSDimitry Andric     case '1':
10275ffd83dbSDimitry Andric     case '2':
10285ffd83dbSDimitry Andric     case '3':
10295ffd83dbSDimitry Andric       T = SVEType(TS, Proto[C - '0']);
10305ffd83dbSDimitry Andric       break;
10315ffd83dbSDimitry Andric     }
10325ffd83dbSDimitry Andric 
10335ffd83dbSDimitry Andric     // Replace templated arg with the right suffix (e.g. u32)
10345ffd83dbSDimitry Andric     std::string TypeCode;
10355ffd83dbSDimitry Andric     if (T.isInteger())
10365ffd83dbSDimitry Andric       TypeCode = T.isSigned() ? 's' : 'u';
103706c3fb27SDimitry Andric     else if (T.isSvcount())
103806c3fb27SDimitry Andric       TypeCode = 'c';
10395ffd83dbSDimitry Andric     else if (T.isPredicateVector())
10405ffd83dbSDimitry Andric       TypeCode = 'b';
10415ffd83dbSDimitry Andric     else if (T.isBFloat())
10425ffd83dbSDimitry Andric       TypeCode = "bf";
10435ffd83dbSDimitry Andric     else
10445ffd83dbSDimitry Andric       TypeCode = 'f';
10455ffd83dbSDimitry Andric     Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits()));
10465ffd83dbSDimitry Andric   }
10475ffd83dbSDimitry Andric 
10485ffd83dbSDimitry Andric   return Ret;
10495ffd83dbSDimitry Andric }
10505ffd83dbSDimitry Andric 
105106c3fb27SDimitry Andric std::string Intrinsic::mangleLLVMName() const {
105206c3fb27SDimitry Andric   std::string S = getLLVMName();
105306c3fb27SDimitry Andric 
105406c3fb27SDimitry Andric   // Replace all {d} like expressions with e.g. 'u32'
105506c3fb27SDimitry Andric   return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto());
105606c3fb27SDimitry Andric }
105706c3fb27SDimitry Andric 
10585ffd83dbSDimitry Andric std::string Intrinsic::mangleName(ClassKind LocalCK) const {
10595ffd83dbSDimitry Andric   std::string S = getName();
10605ffd83dbSDimitry Andric 
10615ffd83dbSDimitry Andric   if (LocalCK == ClassG) {
10625ffd83dbSDimitry Andric     // Remove the square brackets and everything in between.
1063e8d8bef9SDimitry Andric     while (S.find('[') != std::string::npos) {
1064e8d8bef9SDimitry Andric       auto Start = S.find('[');
10655ffd83dbSDimitry Andric       auto End = S.find(']');
10665ffd83dbSDimitry Andric       S.erase(Start, (End-Start)+1);
10675ffd83dbSDimitry Andric     }
10685ffd83dbSDimitry Andric   } else {
10695ffd83dbSDimitry Andric     // Remove the square brackets.
1070e8d8bef9SDimitry Andric     while (S.find('[') != std::string::npos) {
10715ffd83dbSDimitry Andric       auto BrPos = S.find('[');
10725ffd83dbSDimitry Andric       if (BrPos != std::string::npos)
10735ffd83dbSDimitry Andric         S.erase(BrPos, 1);
10745ffd83dbSDimitry Andric       BrPos = S.find(']');
10755ffd83dbSDimitry Andric       if (BrPos != std::string::npos)
10765ffd83dbSDimitry Andric         S.erase(BrPos, 1);
10775ffd83dbSDimitry Andric     }
10785ffd83dbSDimitry Andric   }
10795ffd83dbSDimitry Andric 
10805ffd83dbSDimitry Andric   // Replace all {d} like expressions with e.g. 'u32'
10815ffd83dbSDimitry Andric   return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) +
10825ffd83dbSDimitry Andric          getMergeSuffix();
10835ffd83dbSDimitry Andric }
10845ffd83dbSDimitry Andric 
10855f757f3fSDimitry Andric void Intrinsic::emitIntrinsic(raw_ostream &OS, SVEEmitter &Emitter,
10865f757f3fSDimitry Andric                               ACLEKind Kind) const {
1087fe6060f1SDimitry Andric   bool IsOverloaded = getClassKind() == ClassG && getProto().size() > 1;
10885ffd83dbSDimitry Andric 
1089fe6060f1SDimitry Andric   std::string FullName = mangleName(ClassS);
1090fe6060f1SDimitry Andric   std::string ProtoName = mangleName(getClassKind());
1091fe6060f1SDimitry Andric   OS << (IsOverloaded ? "__aio " : "__ai ")
10925f757f3fSDimitry Andric      << "__attribute__((__clang_arm_builtin_alias(";
10935f757f3fSDimitry Andric 
10945f757f3fSDimitry Andric   switch (Kind) {
10955f757f3fSDimitry Andric   case ACLEKind::SME:
10965f757f3fSDimitry Andric     OS << "__builtin_sme_" << FullName << ")";
10975f757f3fSDimitry Andric     break;
10985f757f3fSDimitry Andric   case ACLEKind::SVE:
10995f757f3fSDimitry Andric     OS << "__builtin_sve_" << FullName << ")";
11005f757f3fSDimitry Andric     break;
11015f757f3fSDimitry Andric   }
11025f757f3fSDimitry Andric 
110306c3fb27SDimitry Andric   OS << "))\n";
11045ffd83dbSDimitry Andric 
11055ffd83dbSDimitry Andric   OS << getTypes()[0].str() << " " << ProtoName << "(";
11065ffd83dbSDimitry Andric   for (unsigned I = 0; I < getTypes().size() - 1; ++I) {
11075ffd83dbSDimitry Andric     if (I != 0)
11085ffd83dbSDimitry Andric       OS << ", ";
11095ffd83dbSDimitry Andric     OS << getTypes()[I + 1].str();
11105ffd83dbSDimitry Andric   }
11115ffd83dbSDimitry Andric   OS << ");\n";
11125ffd83dbSDimitry Andric }
11135ffd83dbSDimitry Andric 
11145ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
11155ffd83dbSDimitry Andric // SVEEmitter implementation
11165ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
11175ffd83dbSDimitry Andric uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) {
11185ffd83dbSDimitry Andric   if (T.isFloat()) {
11195ffd83dbSDimitry Andric     switch (T.getElementSizeInBits()) {
11205ffd83dbSDimitry Andric     case 16:
11215ffd83dbSDimitry Andric       return encodeEltType("EltTyFloat16");
11225ffd83dbSDimitry Andric     case 32:
11235ffd83dbSDimitry Andric       return encodeEltType("EltTyFloat32");
11245ffd83dbSDimitry Andric     case 64:
11255ffd83dbSDimitry Andric       return encodeEltType("EltTyFloat64");
11265ffd83dbSDimitry Andric     default:
11275ffd83dbSDimitry Andric       llvm_unreachable("Unhandled float element bitwidth!");
11285ffd83dbSDimitry Andric     }
11295ffd83dbSDimitry Andric   }
11305ffd83dbSDimitry Andric 
11315ffd83dbSDimitry Andric   if (T.isBFloat()) {
11325ffd83dbSDimitry Andric     assert(T.getElementSizeInBits() == 16 && "Not a valid BFloat.");
11335ffd83dbSDimitry Andric     return encodeEltType("EltTyBFloat16");
11345ffd83dbSDimitry Andric   }
11355ffd83dbSDimitry Andric 
113606c3fb27SDimitry Andric   if (T.isPredicateVector() || T.isSvcount()) {
11375ffd83dbSDimitry Andric     switch (T.getElementSizeInBits()) {
11385ffd83dbSDimitry Andric     case 8:
11395ffd83dbSDimitry Andric       return encodeEltType("EltTyBool8");
11405ffd83dbSDimitry Andric     case 16:
11415ffd83dbSDimitry Andric       return encodeEltType("EltTyBool16");
11425ffd83dbSDimitry Andric     case 32:
11435ffd83dbSDimitry Andric       return encodeEltType("EltTyBool32");
11445ffd83dbSDimitry Andric     case 64:
11455ffd83dbSDimitry Andric       return encodeEltType("EltTyBool64");
11465ffd83dbSDimitry Andric     default:
11475ffd83dbSDimitry Andric       llvm_unreachable("Unhandled predicate element bitwidth!");
11485ffd83dbSDimitry Andric     }
11495ffd83dbSDimitry Andric   }
11505ffd83dbSDimitry Andric 
11515ffd83dbSDimitry Andric   switch (T.getElementSizeInBits()) {
11525ffd83dbSDimitry Andric   case 8:
11535ffd83dbSDimitry Andric     return encodeEltType("EltTyInt8");
11545ffd83dbSDimitry Andric   case 16:
11555ffd83dbSDimitry Andric     return encodeEltType("EltTyInt16");
11565ffd83dbSDimitry Andric   case 32:
11575ffd83dbSDimitry Andric     return encodeEltType("EltTyInt32");
11585ffd83dbSDimitry Andric   case 64:
11595ffd83dbSDimitry Andric     return encodeEltType("EltTyInt64");
116006c3fb27SDimitry Andric   case 128:
116106c3fb27SDimitry Andric     return encodeEltType("EltTyInt128");
11625ffd83dbSDimitry Andric   default:
11635ffd83dbSDimitry Andric     llvm_unreachable("Unhandled integer element bitwidth!");
11645ffd83dbSDimitry Andric   }
11655ffd83dbSDimitry Andric }
11665ffd83dbSDimitry Andric 
11675ffd83dbSDimitry Andric void SVEEmitter::createIntrinsic(
11685ffd83dbSDimitry Andric     Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) {
11695ffd83dbSDimitry Andric   StringRef Name = R->getValueAsString("Name");
11705ffd83dbSDimitry Andric   StringRef Proto = R->getValueAsString("Prototype");
11715ffd83dbSDimitry Andric   StringRef Types = R->getValueAsString("Types");
1172*0fca6ea1SDimitry Andric   StringRef SVEGuard = R->getValueAsString("SVETargetGuard");
1173*0fca6ea1SDimitry Andric   StringRef SMEGuard = R->getValueAsString("SMETargetGuard");
11745ffd83dbSDimitry Andric   StringRef LLVMName = R->getValueAsString("LLVMIntrinsic");
11755ffd83dbSDimitry Andric   uint64_t Merge = R->getValueAsInt("Merge");
11765ffd83dbSDimitry Andric   StringRef MergeSuffix = R->getValueAsString("MergeSuffix");
11775ffd83dbSDimitry Andric   uint64_t MemEltType = R->getValueAsInt("MemEltType");
11785ffd83dbSDimitry Andric   std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags");
11795ffd83dbSDimitry Andric   std::vector<Record*> ImmCheckList = R->getValueAsListOfDefs("ImmChecks");
11805ffd83dbSDimitry Andric 
11815ffd83dbSDimitry Andric   int64_t Flags = 0;
11825ffd83dbSDimitry Andric   for (auto FlagRec : FlagsList)
11835ffd83dbSDimitry Andric     Flags |= FlagRec->getValueAsInt("Value");
11845ffd83dbSDimitry Andric 
11855ffd83dbSDimitry Andric   // Create a dummy TypeSpec for non-overloaded builtins.
11865ffd83dbSDimitry Andric   if (Types.empty()) {
11875ffd83dbSDimitry Andric     assert((Flags & getEnumValueForFlag("IsOverloadNone")) &&
11885ffd83dbSDimitry Andric            "Expect TypeSpec for overloaded builtin!");
11895ffd83dbSDimitry Andric     Types = "i";
11905ffd83dbSDimitry Andric   }
11915ffd83dbSDimitry Andric 
11925ffd83dbSDimitry Andric   // Extract type specs from string
11935ffd83dbSDimitry Andric   SmallVector<TypeSpec, 8> TypeSpecs;
11945ffd83dbSDimitry Andric   TypeSpec Acc;
11955ffd83dbSDimitry Andric   for (char I : Types) {
11965ffd83dbSDimitry Andric     Acc.push_back(I);
11975ffd83dbSDimitry Andric     if (islower(I)) {
11985ffd83dbSDimitry Andric       TypeSpecs.push_back(TypeSpec(Acc));
11995ffd83dbSDimitry Andric       Acc.clear();
12005ffd83dbSDimitry Andric     }
12015ffd83dbSDimitry Andric   }
12025ffd83dbSDimitry Andric 
12035ffd83dbSDimitry Andric   // Remove duplicate type specs.
12045ffd83dbSDimitry Andric   llvm::sort(TypeSpecs);
12055ffd83dbSDimitry Andric   TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()),
12065ffd83dbSDimitry Andric                   TypeSpecs.end());
12075ffd83dbSDimitry Andric 
12085ffd83dbSDimitry Andric   // Create an Intrinsic for each type spec.
12095ffd83dbSDimitry Andric   for (auto TS : TypeSpecs) {
12105ffd83dbSDimitry Andric     // Collate a list of range/option checks for the immediates.
12115ffd83dbSDimitry Andric     SmallVector<ImmCheck, 2> ImmChecks;
12125ffd83dbSDimitry Andric     for (auto *R : ImmCheckList) {
12135ffd83dbSDimitry Andric       int64_t Arg = R->getValueAsInt("Arg");
12145ffd83dbSDimitry Andric       int64_t EltSizeArg = R->getValueAsInt("EltSizeArg");
12155ffd83dbSDimitry Andric       int64_t Kind = R->getValueAsDef("Kind")->getValueAsInt("Value");
12165ffd83dbSDimitry Andric       assert(Arg >= 0 && Kind >= 0 && "Arg and Kind must be nonnegative");
12175ffd83dbSDimitry Andric 
12185ffd83dbSDimitry Andric       unsigned ElementSizeInBits = 0;
12195f757f3fSDimitry Andric       char Mod;
12205f757f3fSDimitry Andric       unsigned NumVectors;
12215f757f3fSDimitry Andric       std::tie(Mod, NumVectors) = getProtoModifier(Proto, EltSizeArg + 1);
12225ffd83dbSDimitry Andric       if (EltSizeArg >= 0)
12235f757f3fSDimitry Andric         ElementSizeInBits = SVEType(TS, Mod, NumVectors).getElementSizeInBits();
12245ffd83dbSDimitry Andric       ImmChecks.push_back(ImmCheck(Arg, Kind, ElementSizeInBits));
12255ffd83dbSDimitry Andric     }
12265ffd83dbSDimitry Andric 
12275ffd83dbSDimitry Andric     Out.push_back(std::make_unique<Intrinsic>(
12285ffd83dbSDimitry Andric         Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, ImmChecks,
1229*0fca6ea1SDimitry Andric         TS, ClassS, *this, SVEGuard, SMEGuard));
12305ffd83dbSDimitry Andric 
12315ffd83dbSDimitry Andric     // Also generate the short-form (e.g. svadd_m) for the given type-spec.
12325ffd83dbSDimitry Andric     if (Intrinsic::isOverloadedIntrinsic(Name))
12335ffd83dbSDimitry Andric       Out.push_back(std::make_unique<Intrinsic>(
12345ffd83dbSDimitry Andric           Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags,
1235*0fca6ea1SDimitry Andric           ImmChecks, TS, ClassG, *this, SVEGuard, SMEGuard));
12365ffd83dbSDimitry Andric   }
12375ffd83dbSDimitry Andric }
12385ffd83dbSDimitry Andric 
12395f757f3fSDimitry Andric void SVEEmitter::createCoreHeaderIntrinsics(raw_ostream &OS,
12405f757f3fSDimitry Andric                                             SVEEmitter &Emitter,
12415f757f3fSDimitry Andric                                             ACLEKind Kind) {
12425f757f3fSDimitry Andric   SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
12435f757f3fSDimitry Andric   std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
12445f757f3fSDimitry Andric   for (auto *R : RV)
12455f757f3fSDimitry Andric     createIntrinsic(R, Defs);
12465f757f3fSDimitry Andric 
12475f757f3fSDimitry Andric   // Sort intrinsics in header file by following order/priority:
12485f757f3fSDimitry Andric   // - Architectural guard (i.e. does it require SVE2 or SVE2_AES)
12495f757f3fSDimitry Andric   // - Class (is intrinsic overloaded or not)
12505f757f3fSDimitry Andric   // - Intrinsic name
12515f757f3fSDimitry Andric   std::stable_sort(Defs.begin(), Defs.end(),
12525f757f3fSDimitry Andric                    [](const std::unique_ptr<Intrinsic> &A,
12535f757f3fSDimitry Andric                       const std::unique_ptr<Intrinsic> &B) {
12545f757f3fSDimitry Andric                      auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) {
1255*0fca6ea1SDimitry Andric                        return std::make_tuple(
1256*0fca6ea1SDimitry Andric                            I->getSVEGuard().str() + I->getSMEGuard().str(),
1257*0fca6ea1SDimitry Andric                            (unsigned)I->getClassKind(), I->getName());
12585f757f3fSDimitry Andric                      };
12595f757f3fSDimitry Andric                      return ToTuple(A) < ToTuple(B);
12605f757f3fSDimitry Andric                    });
12615f757f3fSDimitry Andric 
12625f757f3fSDimitry Andric   // Actually emit the intrinsic declarations.
12635f757f3fSDimitry Andric   for (auto &I : Defs)
12645f757f3fSDimitry Andric     I->emitIntrinsic(OS, Emitter, Kind);
12655f757f3fSDimitry Andric }
12665f757f3fSDimitry Andric 
12675ffd83dbSDimitry Andric void SVEEmitter::createHeader(raw_ostream &OS) {
12685ffd83dbSDimitry Andric   OS << "/*===---- arm_sve.h - ARM SVE intrinsics "
12695ffd83dbSDimitry Andric         "-----------------------------------===\n"
12705ffd83dbSDimitry Andric         " *\n"
12715ffd83dbSDimitry Andric         " *\n"
12725ffd83dbSDimitry Andric         " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
12735ffd83dbSDimitry Andric         "Exceptions.\n"
12745ffd83dbSDimitry Andric         " * See https://llvm.org/LICENSE.txt for license information.\n"
12755ffd83dbSDimitry Andric         " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
12765ffd83dbSDimitry Andric         " *\n"
12775ffd83dbSDimitry Andric         " *===-----------------------------------------------------------------"
12785ffd83dbSDimitry Andric         "------===\n"
12795ffd83dbSDimitry Andric         " */\n\n";
12805ffd83dbSDimitry Andric 
12815ffd83dbSDimitry Andric   OS << "#ifndef __ARM_SVE_H\n";
12825ffd83dbSDimitry Andric   OS << "#define __ARM_SVE_H\n\n";
12835ffd83dbSDimitry Andric 
12845ffd83dbSDimitry Andric   OS << "#if !defined(__LITTLE_ENDIAN__)\n";
12855ffd83dbSDimitry Andric   OS << "#error \"Big endian is currently not supported for arm_sve.h\"\n";
12865ffd83dbSDimitry Andric   OS << "#endif\n";
12875ffd83dbSDimitry Andric 
12885ffd83dbSDimitry Andric   OS << "#include <stdint.h>\n\n";
12895ffd83dbSDimitry Andric   OS << "#ifdef  __cplusplus\n";
12905ffd83dbSDimitry Andric   OS << "extern \"C\" {\n";
12915ffd83dbSDimitry Andric   OS << "#else\n";
12925ffd83dbSDimitry Andric   OS << "#include <stdbool.h>\n";
12935ffd83dbSDimitry Andric   OS << "#endif\n\n";
12945ffd83dbSDimitry Andric 
12955ffd83dbSDimitry Andric   OS << "typedef __fp16 float16_t;\n";
12965ffd83dbSDimitry Andric   OS << "typedef float float32_t;\n";
12975ffd83dbSDimitry Andric   OS << "typedef double float64_t;\n";
12985ffd83dbSDimitry Andric 
12995ffd83dbSDimitry Andric   OS << "typedef __SVInt8_t svint8_t;\n";
13005ffd83dbSDimitry Andric   OS << "typedef __SVInt16_t svint16_t;\n";
13015ffd83dbSDimitry Andric   OS << "typedef __SVInt32_t svint32_t;\n";
13025ffd83dbSDimitry Andric   OS << "typedef __SVInt64_t svint64_t;\n";
13035ffd83dbSDimitry Andric   OS << "typedef __SVUint8_t svuint8_t;\n";
13045ffd83dbSDimitry Andric   OS << "typedef __SVUint16_t svuint16_t;\n";
13055ffd83dbSDimitry Andric   OS << "typedef __SVUint32_t svuint32_t;\n";
13065ffd83dbSDimitry Andric   OS << "typedef __SVUint64_t svuint64_t;\n";
13075ffd83dbSDimitry Andric   OS << "typedef __SVFloat16_t svfloat16_t;\n\n";
13085ffd83dbSDimitry Andric 
13095f757f3fSDimitry Andric   OS << "typedef __SVBfloat16_t svbfloat16_t;\n";
13105ffd83dbSDimitry Andric 
13115ffd83dbSDimitry Andric   OS << "#include <arm_bf16.h>\n";
13125f757f3fSDimitry Andric   OS << "#include <arm_vector_types.h>\n";
13135ffd83dbSDimitry Andric 
13145ffd83dbSDimitry Andric   OS << "typedef __SVFloat32_t svfloat32_t;\n";
13155ffd83dbSDimitry Andric   OS << "typedef __SVFloat64_t svfloat64_t;\n";
13165ffd83dbSDimitry Andric   OS << "typedef __clang_svint8x2_t svint8x2_t;\n";
13175ffd83dbSDimitry Andric   OS << "typedef __clang_svint16x2_t svint16x2_t;\n";
13185ffd83dbSDimitry Andric   OS << "typedef __clang_svint32x2_t svint32x2_t;\n";
13195ffd83dbSDimitry Andric   OS << "typedef __clang_svint64x2_t svint64x2_t;\n";
13205ffd83dbSDimitry Andric   OS << "typedef __clang_svuint8x2_t svuint8x2_t;\n";
13215ffd83dbSDimitry Andric   OS << "typedef __clang_svuint16x2_t svuint16x2_t;\n";
13225ffd83dbSDimitry Andric   OS << "typedef __clang_svuint32x2_t svuint32x2_t;\n";
13235ffd83dbSDimitry Andric   OS << "typedef __clang_svuint64x2_t svuint64x2_t;\n";
13245ffd83dbSDimitry Andric   OS << "typedef __clang_svfloat16x2_t svfloat16x2_t;\n";
13255ffd83dbSDimitry Andric   OS << "typedef __clang_svfloat32x2_t svfloat32x2_t;\n";
13265ffd83dbSDimitry Andric   OS << "typedef __clang_svfloat64x2_t svfloat64x2_t;\n";
13275ffd83dbSDimitry Andric   OS << "typedef __clang_svint8x3_t svint8x3_t;\n";
13285ffd83dbSDimitry Andric   OS << "typedef __clang_svint16x3_t svint16x3_t;\n";
13295ffd83dbSDimitry Andric   OS << "typedef __clang_svint32x3_t svint32x3_t;\n";
13305ffd83dbSDimitry Andric   OS << "typedef __clang_svint64x3_t svint64x3_t;\n";
13315ffd83dbSDimitry Andric   OS << "typedef __clang_svuint8x3_t svuint8x3_t;\n";
13325ffd83dbSDimitry Andric   OS << "typedef __clang_svuint16x3_t svuint16x3_t;\n";
13335ffd83dbSDimitry Andric   OS << "typedef __clang_svuint32x3_t svuint32x3_t;\n";
13345ffd83dbSDimitry Andric   OS << "typedef __clang_svuint64x3_t svuint64x3_t;\n";
13355ffd83dbSDimitry Andric   OS << "typedef __clang_svfloat16x3_t svfloat16x3_t;\n";
13365ffd83dbSDimitry Andric   OS << "typedef __clang_svfloat32x3_t svfloat32x3_t;\n";
13375ffd83dbSDimitry Andric   OS << "typedef __clang_svfloat64x3_t svfloat64x3_t;\n";
13385ffd83dbSDimitry Andric   OS << "typedef __clang_svint8x4_t svint8x4_t;\n";
13395ffd83dbSDimitry Andric   OS << "typedef __clang_svint16x4_t svint16x4_t;\n";
13405ffd83dbSDimitry Andric   OS << "typedef __clang_svint32x4_t svint32x4_t;\n";
13415ffd83dbSDimitry Andric   OS << "typedef __clang_svint64x4_t svint64x4_t;\n";
13425ffd83dbSDimitry Andric   OS << "typedef __clang_svuint8x4_t svuint8x4_t;\n";
13435ffd83dbSDimitry Andric   OS << "typedef __clang_svuint16x4_t svuint16x4_t;\n";
13445ffd83dbSDimitry Andric   OS << "typedef __clang_svuint32x4_t svuint32x4_t;\n";
13455ffd83dbSDimitry Andric   OS << "typedef __clang_svuint64x4_t svuint64x4_t;\n";
13465ffd83dbSDimitry Andric   OS << "typedef __clang_svfloat16x4_t svfloat16x4_t;\n";
13475ffd83dbSDimitry Andric   OS << "typedef __clang_svfloat32x4_t svfloat32x4_t;\n";
13485ffd83dbSDimitry Andric   OS << "typedef __clang_svfloat64x4_t svfloat64x4_t;\n";
134906c3fb27SDimitry Andric   OS << "typedef __SVBool_t  svbool_t;\n";
135006c3fb27SDimitry Andric   OS << "typedef __clang_svboolx2_t  svboolx2_t;\n";
135106c3fb27SDimitry Andric   OS << "typedef __clang_svboolx4_t  svboolx4_t;\n\n";
13525ffd83dbSDimitry Andric 
13535ffd83dbSDimitry Andric   OS << "typedef __clang_svbfloat16x2_t svbfloat16x2_t;\n";
13545ffd83dbSDimitry Andric   OS << "typedef __clang_svbfloat16x3_t svbfloat16x3_t;\n";
13555ffd83dbSDimitry Andric   OS << "typedef __clang_svbfloat16x4_t svbfloat16x4_t;\n";
13565ffd83dbSDimitry Andric 
135706c3fb27SDimitry Andric   OS << "typedef __SVCount_t svcount_t;\n\n";
135806c3fb27SDimitry Andric 
1359e8d8bef9SDimitry Andric   OS << "enum svpattern\n";
13605ffd83dbSDimitry Andric   OS << "{\n";
13615ffd83dbSDimitry Andric   OS << "  SV_POW2 = 0,\n";
13625ffd83dbSDimitry Andric   OS << "  SV_VL1 = 1,\n";
13635ffd83dbSDimitry Andric   OS << "  SV_VL2 = 2,\n";
13645ffd83dbSDimitry Andric   OS << "  SV_VL3 = 3,\n";
13655ffd83dbSDimitry Andric   OS << "  SV_VL4 = 4,\n";
13665ffd83dbSDimitry Andric   OS << "  SV_VL5 = 5,\n";
13675ffd83dbSDimitry Andric   OS << "  SV_VL6 = 6,\n";
13685ffd83dbSDimitry Andric   OS << "  SV_VL7 = 7,\n";
13695ffd83dbSDimitry Andric   OS << "  SV_VL8 = 8,\n";
13705ffd83dbSDimitry Andric   OS << "  SV_VL16 = 9,\n";
13715ffd83dbSDimitry Andric   OS << "  SV_VL32 = 10,\n";
13725ffd83dbSDimitry Andric   OS << "  SV_VL64 = 11,\n";
13735ffd83dbSDimitry Andric   OS << "  SV_VL128 = 12,\n";
13745ffd83dbSDimitry Andric   OS << "  SV_VL256 = 13,\n";
13755ffd83dbSDimitry Andric   OS << "  SV_MUL4 = 29,\n";
13765ffd83dbSDimitry Andric   OS << "  SV_MUL3 = 30,\n";
13775ffd83dbSDimitry Andric   OS << "  SV_ALL = 31\n";
1378e8d8bef9SDimitry Andric   OS << "};\n\n";
13795ffd83dbSDimitry Andric 
1380e8d8bef9SDimitry Andric   OS << "enum svprfop\n";
13815ffd83dbSDimitry Andric   OS << "{\n";
13825ffd83dbSDimitry Andric   OS << "  SV_PLDL1KEEP = 0,\n";
13835ffd83dbSDimitry Andric   OS << "  SV_PLDL1STRM = 1,\n";
13845ffd83dbSDimitry Andric   OS << "  SV_PLDL2KEEP = 2,\n";
13855ffd83dbSDimitry Andric   OS << "  SV_PLDL2STRM = 3,\n";
13865ffd83dbSDimitry Andric   OS << "  SV_PLDL3KEEP = 4,\n";
13875ffd83dbSDimitry Andric   OS << "  SV_PLDL3STRM = 5,\n";
13885ffd83dbSDimitry Andric   OS << "  SV_PSTL1KEEP = 8,\n";
13895ffd83dbSDimitry Andric   OS << "  SV_PSTL1STRM = 9,\n";
13905ffd83dbSDimitry Andric   OS << "  SV_PSTL2KEEP = 10,\n";
13915ffd83dbSDimitry Andric   OS << "  SV_PSTL2STRM = 11,\n";
13925ffd83dbSDimitry Andric   OS << "  SV_PSTL3KEEP = 12,\n";
13935ffd83dbSDimitry Andric   OS << "  SV_PSTL3STRM = 13\n";
1394e8d8bef9SDimitry Andric   OS << "};\n\n";
13955ffd83dbSDimitry Andric 
13965ffd83dbSDimitry Andric   OS << "/* Function attributes */\n";
1397fe6060f1SDimitry Andric   OS << "#define __ai static __inline__ __attribute__((__always_inline__, "
1398fe6060f1SDimitry Andric         "__nodebug__))\n\n";
1399fe6060f1SDimitry Andric   OS << "#define __aio static __inline__ __attribute__((__always_inline__, "
14005ffd83dbSDimitry Andric         "__nodebug__, __overloadable__))\n\n";
14015ffd83dbSDimitry Andric 
14025ffd83dbSDimitry Andric   // Add reinterpret functions.
14035f757f3fSDimitry Andric   for (auto [N, Suffix] :
14045f757f3fSDimitry Andric        std::initializer_list<std::pair<unsigned, const char *>>{
14055f757f3fSDimitry Andric            {1, ""}, {2, "_x2"}, {3, "_x3"}, {4, "_x4"}}) {
14065ffd83dbSDimitry Andric     for (auto ShortForm : {false, true})
14075ffd83dbSDimitry Andric       for (const ReinterpretTypeInfo &To : Reinterprets) {
14085f757f3fSDimitry Andric         SVEType ToV(To.BaseType, N);
14095f757f3fSDimitry Andric         for (const ReinterpretTypeInfo &From : Reinterprets) {
14105f757f3fSDimitry Andric           SVEType FromV(From.BaseType, N);
1411*0fca6ea1SDimitry Andric           OS << "__aio "
1412*0fca6ea1SDimitry Andric                 "__attribute__((__clang_arm_builtin_alias(__builtin_sve_"
1413*0fca6ea1SDimitry Andric                 "reinterpret_"
1414*0fca6ea1SDimitry Andric              << To.Suffix << "_" << From.Suffix << Suffix << ")))\n"
1415*0fca6ea1SDimitry Andric              << ToV.str() << " svreinterpret_" << To.Suffix;
1416*0fca6ea1SDimitry Andric           if (!ShortForm)
1417*0fca6ea1SDimitry Andric             OS << "_" << From.Suffix << Suffix;
1418*0fca6ea1SDimitry Andric           OS << "(" << FromV.str() << " op);\n";
14195f757f3fSDimitry Andric         }
14205f757f3fSDimitry Andric       }
14215ffd83dbSDimitry Andric   }
14225ffd83dbSDimitry Andric 
14235f757f3fSDimitry Andric   createCoreHeaderIntrinsics(OS, *this, ACLEKind::SVE);
14245ffd83dbSDimitry Andric 
14255ffd83dbSDimitry Andric   OS << "#define svcvtnt_bf16_x      svcvtnt_bf16_m\n";
14265ffd83dbSDimitry Andric   OS << "#define svcvtnt_bf16_f32_x  svcvtnt_bf16_f32_m\n";
14275ffd83dbSDimitry Andric 
14285ffd83dbSDimitry Andric   OS << "#define svcvtnt_f16_x      svcvtnt_f16_m\n";
14295ffd83dbSDimitry Andric   OS << "#define svcvtnt_f16_f32_x  svcvtnt_f16_f32_m\n";
14305ffd83dbSDimitry Andric   OS << "#define svcvtnt_f32_x      svcvtnt_f32_m\n";
14315ffd83dbSDimitry Andric   OS << "#define svcvtnt_f32_f64_x  svcvtnt_f32_f64_m\n\n";
14325ffd83dbSDimitry Andric 
14335ffd83dbSDimitry Andric   OS << "#define svcvtxnt_f32_x     svcvtxnt_f32_m\n";
14345ffd83dbSDimitry Andric   OS << "#define svcvtxnt_f32_f64_x svcvtxnt_f32_f64_m\n\n";
14355ffd83dbSDimitry Andric 
14365ffd83dbSDimitry Andric   OS << "#ifdef __cplusplus\n";
14375ffd83dbSDimitry Andric   OS << "} // extern \"C\"\n";
14385ffd83dbSDimitry Andric   OS << "#endif\n\n";
1439a4a491e2SDimitry Andric   OS << "#undef __ai\n\n";
1440a4a491e2SDimitry Andric   OS << "#undef __aio\n\n";
14415ffd83dbSDimitry Andric   OS << "#endif /* __ARM_SVE_H */\n";
14425ffd83dbSDimitry Andric }
14435ffd83dbSDimitry Andric 
14445ffd83dbSDimitry Andric void SVEEmitter::createBuiltins(raw_ostream &OS) {
14455ffd83dbSDimitry Andric   std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
14465ffd83dbSDimitry Andric   SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
14475ffd83dbSDimitry Andric   for (auto *R : RV)
14485ffd83dbSDimitry Andric     createIntrinsic(R, Defs);
14495ffd83dbSDimitry Andric 
14505ffd83dbSDimitry Andric   // The mappings must be sorted based on BuiltinID.
14515ffd83dbSDimitry Andric   llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
14525ffd83dbSDimitry Andric                       const std::unique_ptr<Intrinsic> &B) {
14535ffd83dbSDimitry Andric     return A->getMangledName() < B->getMangledName();
14545ffd83dbSDimitry Andric   });
14555ffd83dbSDimitry Andric 
14565ffd83dbSDimitry Andric   OS << "#ifdef GET_SVE_BUILTINS\n";
14575ffd83dbSDimitry Andric   for (auto &Def : Defs) {
14585ffd83dbSDimitry Andric     // Only create BUILTINs for non-overloaded intrinsics, as overloaded
14595ffd83dbSDimitry Andric     // declarations only live in the header file.
1460*0fca6ea1SDimitry Andric     if (Def->getClassKind() != ClassG) {
1461bdd1243dSDimitry Andric       OS << "TARGET_BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \""
1462*0fca6ea1SDimitry Andric          << Def->getBuiltinTypeStr() << "\", \"n\", \"";
1463*0fca6ea1SDimitry Andric       Def->printGuard(OS);
1464*0fca6ea1SDimitry Andric       OS << "\")\n";
1465*0fca6ea1SDimitry Andric     }
14665ffd83dbSDimitry Andric   }
14675ffd83dbSDimitry Andric 
14685f757f3fSDimitry Andric   // Add reinterpret functions.
14695f757f3fSDimitry Andric   for (auto [N, Suffix] :
14705f757f3fSDimitry Andric        std::initializer_list<std::pair<unsigned, const char *>>{
14715f757f3fSDimitry Andric            {1, ""}, {2, "_x2"}, {3, "_x3"}, {4, "_x4"}}) {
14725f757f3fSDimitry Andric     for (const ReinterpretTypeInfo &To : Reinterprets) {
14735f757f3fSDimitry Andric       SVEType ToV(To.BaseType, N);
14745f757f3fSDimitry Andric       for (const ReinterpretTypeInfo &From : Reinterprets) {
14755f757f3fSDimitry Andric         SVEType FromV(From.BaseType, N);
14765f757f3fSDimitry Andric         OS << "TARGET_BUILTIN(__builtin_sve_reinterpret_" << To.Suffix << "_"
14775f757f3fSDimitry Andric            << From.Suffix << Suffix << +", \"" << ToV.builtin_str()
1478*0fca6ea1SDimitry Andric            << FromV.builtin_str() << "\", \"n\", \"sme|sve\")\n";
14795f757f3fSDimitry Andric       }
14805f757f3fSDimitry Andric     }
14815f757f3fSDimitry Andric   }
14825ffd83dbSDimitry Andric 
14835ffd83dbSDimitry Andric   OS << "#endif\n\n";
14845ffd83dbSDimitry Andric }
14855ffd83dbSDimitry Andric 
14865ffd83dbSDimitry Andric void SVEEmitter::createCodeGenMap(raw_ostream &OS) {
14875ffd83dbSDimitry Andric   std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
14885ffd83dbSDimitry Andric   SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
14895ffd83dbSDimitry Andric   for (auto *R : RV)
14905ffd83dbSDimitry Andric     createIntrinsic(R, Defs);
14915ffd83dbSDimitry Andric 
14925ffd83dbSDimitry Andric   // The mappings must be sorted based on BuiltinID.
14935ffd83dbSDimitry Andric   llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
14945ffd83dbSDimitry Andric                       const std::unique_ptr<Intrinsic> &B) {
14955ffd83dbSDimitry Andric     return A->getMangledName() < B->getMangledName();
14965ffd83dbSDimitry Andric   });
14975ffd83dbSDimitry Andric 
14985ffd83dbSDimitry Andric   OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n";
14995ffd83dbSDimitry Andric   for (auto &Def : Defs) {
15005ffd83dbSDimitry Andric     // Builtins only exist for non-overloaded intrinsics, overloaded
15015ffd83dbSDimitry Andric     // declarations only live in the header file.
15025ffd83dbSDimitry Andric     if (Def->getClassKind() == ClassG)
15035ffd83dbSDimitry Andric       continue;
15045ffd83dbSDimitry Andric 
15055ffd83dbSDimitry Andric     uint64_t Flags = Def->getFlags();
15065ffd83dbSDimitry Andric     auto FlagString = std::to_string(Flags);
15075ffd83dbSDimitry Andric 
150806c3fb27SDimitry Andric     std::string LLVMName = Def->getMangledLLVMName();
15095ffd83dbSDimitry Andric     std::string Builtin = Def->getMangledName();
15105ffd83dbSDimitry Andric     if (!LLVMName.empty())
15115ffd83dbSDimitry Andric       OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
15125ffd83dbSDimitry Andric          << "),\n";
15135ffd83dbSDimitry Andric     else
15145ffd83dbSDimitry Andric       OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n";
15155ffd83dbSDimitry Andric   }
15165ffd83dbSDimitry Andric   OS << "#endif\n\n";
15175ffd83dbSDimitry Andric }
15185ffd83dbSDimitry Andric 
15195ffd83dbSDimitry Andric void SVEEmitter::createRangeChecks(raw_ostream &OS) {
15205ffd83dbSDimitry Andric   std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
15215ffd83dbSDimitry Andric   SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
15225ffd83dbSDimitry Andric   for (auto *R : RV)
15235ffd83dbSDimitry Andric     createIntrinsic(R, Defs);
15245ffd83dbSDimitry Andric 
15255ffd83dbSDimitry Andric   // The mappings must be sorted based on BuiltinID.
15265ffd83dbSDimitry Andric   llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
15275ffd83dbSDimitry Andric                       const std::unique_ptr<Intrinsic> &B) {
15285ffd83dbSDimitry Andric     return A->getMangledName() < B->getMangledName();
15295ffd83dbSDimitry Andric   });
15305ffd83dbSDimitry Andric 
15315ffd83dbSDimitry Andric 
15325ffd83dbSDimitry Andric   OS << "#ifdef GET_SVE_IMMEDIATE_CHECK\n";
15335ffd83dbSDimitry Andric 
15345ffd83dbSDimitry Andric   // Ensure these are only emitted once.
15355ffd83dbSDimitry Andric   std::set<std::string> Emitted;
15365ffd83dbSDimitry Andric 
15375ffd83dbSDimitry Andric   for (auto &Def : Defs) {
15385ffd83dbSDimitry Andric     if (Emitted.find(Def->getMangledName()) != Emitted.end() ||
15395ffd83dbSDimitry Andric         Def->getImmChecks().empty())
15405ffd83dbSDimitry Andric       continue;
15415ffd83dbSDimitry Andric 
15425ffd83dbSDimitry Andric     OS << "case SVE::BI__builtin_sve_" << Def->getMangledName() << ":\n";
15435ffd83dbSDimitry Andric     for (auto &Check : Def->getImmChecks())
15445ffd83dbSDimitry Andric       OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", "
15455ffd83dbSDimitry Andric          << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n";
15465ffd83dbSDimitry Andric     OS << "  break;\n";
15475ffd83dbSDimitry Andric 
15485ffd83dbSDimitry Andric     Emitted.insert(Def->getMangledName());
15495ffd83dbSDimitry Andric   }
15505ffd83dbSDimitry Andric 
15515ffd83dbSDimitry Andric   OS << "#endif\n\n";
15525ffd83dbSDimitry Andric }
15535ffd83dbSDimitry Andric 
15545ffd83dbSDimitry Andric /// Create the SVETypeFlags used in CGBuiltins
15555ffd83dbSDimitry Andric void SVEEmitter::createTypeFlags(raw_ostream &OS) {
15565ffd83dbSDimitry Andric   OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n";
15575ffd83dbSDimitry Andric   for (auto &KV : FlagTypes)
15585ffd83dbSDimitry Andric     OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n";
15595ffd83dbSDimitry Andric   OS << "#endif\n\n";
15605ffd83dbSDimitry Andric 
15615ffd83dbSDimitry Andric   OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n";
15625ffd83dbSDimitry Andric   for (auto &KV : EltTypes)
15635ffd83dbSDimitry Andric     OS << "  " << KV.getKey() << " = " << KV.getValue() << ",\n";
15645ffd83dbSDimitry Andric   OS << "#endif\n\n";
15655ffd83dbSDimitry Andric 
15665ffd83dbSDimitry Andric   OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n";
15675ffd83dbSDimitry Andric   for (auto &KV : MemEltTypes)
15685ffd83dbSDimitry Andric     OS << "  " << KV.getKey() << " = " << KV.getValue() << ",\n";
15695ffd83dbSDimitry Andric   OS << "#endif\n\n";
15705ffd83dbSDimitry Andric 
15715ffd83dbSDimitry Andric   OS << "#ifdef LLVM_GET_SVE_MERGETYPES\n";
15725ffd83dbSDimitry Andric   for (auto &KV : MergeTypes)
15735ffd83dbSDimitry Andric     OS << "  " << KV.getKey() << " = " << KV.getValue() << ",\n";
15745ffd83dbSDimitry Andric   OS << "#endif\n\n";
15755ffd83dbSDimitry Andric 
15765ffd83dbSDimitry Andric   OS << "#ifdef LLVM_GET_SVE_IMMCHECKTYPES\n";
15775ffd83dbSDimitry Andric   for (auto &KV : ImmCheckTypes)
15785ffd83dbSDimitry Andric     OS << "  " << KV.getKey() << " = " << KV.getValue() << ",\n";
15795ffd83dbSDimitry Andric   OS << "#endif\n\n";
15805ffd83dbSDimitry Andric }
15815ffd83dbSDimitry Andric 
158206c3fb27SDimitry Andric void SVEEmitter::createSMEHeader(raw_ostream &OS) {
15837a6dacacSDimitry Andric   OS << "/*===---- arm_sme.h - ARM SME intrinsics "
158406c3fb27SDimitry Andric         "------===\n"
158506c3fb27SDimitry Andric         " *\n"
158606c3fb27SDimitry Andric         " *\n"
158706c3fb27SDimitry Andric         " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
158806c3fb27SDimitry Andric         "Exceptions.\n"
158906c3fb27SDimitry Andric         " * See https://llvm.org/LICENSE.txt for license information.\n"
159006c3fb27SDimitry Andric         " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
159106c3fb27SDimitry Andric         " *\n"
159206c3fb27SDimitry Andric         " *===-----------------------------------------------------------------"
159306c3fb27SDimitry Andric         "------===\n"
159406c3fb27SDimitry Andric         " */\n\n";
159506c3fb27SDimitry Andric 
159606c3fb27SDimitry Andric   OS << "#ifndef __ARM_SME_H\n";
159706c3fb27SDimitry Andric   OS << "#define __ARM_SME_H\n\n";
159806c3fb27SDimitry Andric 
159906c3fb27SDimitry Andric   OS << "#if !defined(__LITTLE_ENDIAN__)\n";
16007a6dacacSDimitry Andric   OS << "#error \"Big endian is currently not supported for arm_sme.h\"\n";
160106c3fb27SDimitry Andric   OS << "#endif\n";
160206c3fb27SDimitry Andric 
160306c3fb27SDimitry Andric   OS << "#include <arm_sve.h>\n\n";
1604*0fca6ea1SDimitry Andric   OS << "#include <stddef.h>\n\n";
160506c3fb27SDimitry Andric 
160606c3fb27SDimitry Andric   OS << "/* Function attributes */\n";
160706c3fb27SDimitry Andric   OS << "#define __ai static __inline__ __attribute__((__always_inline__, "
160806c3fb27SDimitry Andric         "__nodebug__))\n\n";
160906c3fb27SDimitry Andric   OS << "#define __aio static __inline__ __attribute__((__always_inline__, "
161006c3fb27SDimitry Andric         "__nodebug__, __overloadable__))\n\n";
161106c3fb27SDimitry Andric 
161206c3fb27SDimitry Andric   OS << "#ifdef  __cplusplus\n";
161306c3fb27SDimitry Andric   OS << "extern \"C\" {\n";
161406c3fb27SDimitry Andric   OS << "#endif\n\n";
161506c3fb27SDimitry Andric 
1616647cbc5dSDimitry Andric   OS << "void __arm_za_disable(void) __arm_streaming_compatible;\n\n";
1617647cbc5dSDimitry Andric 
1618647cbc5dSDimitry Andric   OS << "__ai bool __arm_has_sme(void) __arm_streaming_compatible {\n";
1619647cbc5dSDimitry Andric   OS << "  uint64_t x0, x1;\n";
1620647cbc5dSDimitry Andric   OS << "  __builtin_arm_get_sme_state(&x0, &x1);\n";
1621647cbc5dSDimitry Andric   OS << "  return x0 & (1ULL << 63);\n";
1622647cbc5dSDimitry Andric   OS << "}\n\n";
1623647cbc5dSDimitry Andric 
1624647cbc5dSDimitry Andric   OS << "__ai bool __arm_in_streaming_mode(void) __arm_streaming_compatible "
1625647cbc5dSDimitry Andric         "{\n";
1626647cbc5dSDimitry Andric   OS << "  uint64_t x0, x1;\n";
1627647cbc5dSDimitry Andric   OS << "  __builtin_arm_get_sme_state(&x0, &x1);\n";
1628647cbc5dSDimitry Andric   OS << "  return x0 & 1;\n";
1629647cbc5dSDimitry Andric   OS << "}\n\n";
1630647cbc5dSDimitry Andric 
1631*0fca6ea1SDimitry Andric   OS << "void *__arm_sc_memcpy(void *dest, const void *src, size_t n) __arm_streaming_compatible;\n";
1632*0fca6ea1SDimitry Andric   OS << "void *__arm_sc_memmove(void *dest, const void *src, size_t n) __arm_streaming_compatible;\n";
1633*0fca6ea1SDimitry Andric   OS << "void *__arm_sc_memset(void *s, int c, size_t n) __arm_streaming_compatible;\n";
1634*0fca6ea1SDimitry Andric   OS << "void *__arm_sc_memchr(void *s, int c, size_t n) __arm_streaming_compatible;\n\n";
1635*0fca6ea1SDimitry Andric 
1636647cbc5dSDimitry Andric   OS << "__ai __attribute__((target(\"sme\"))) void svundef_za(void) "
16377a6dacacSDimitry Andric         "__arm_streaming_compatible __arm_out(\"za\") "
1638647cbc5dSDimitry Andric         "{ }\n\n";
1639647cbc5dSDimitry Andric 
16405f757f3fSDimitry Andric   createCoreHeaderIntrinsics(OS, *this, ACLEKind::SME);
164106c3fb27SDimitry Andric 
164206c3fb27SDimitry Andric   OS << "#ifdef __cplusplus\n";
164306c3fb27SDimitry Andric   OS << "} // extern \"C\"\n";
164406c3fb27SDimitry Andric   OS << "#endif\n\n";
164506c3fb27SDimitry Andric   OS << "#undef __ai\n\n";
164606c3fb27SDimitry Andric   OS << "#endif /* __ARM_SME_H */\n";
164706c3fb27SDimitry Andric }
164806c3fb27SDimitry Andric 
164906c3fb27SDimitry Andric void SVEEmitter::createSMEBuiltins(raw_ostream &OS) {
165006c3fb27SDimitry Andric   std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
165106c3fb27SDimitry Andric   SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
165206c3fb27SDimitry Andric   for (auto *R : RV) {
165306c3fb27SDimitry Andric     createIntrinsic(R, Defs);
165406c3fb27SDimitry Andric   }
165506c3fb27SDimitry Andric 
165606c3fb27SDimitry Andric   // The mappings must be sorted based on BuiltinID.
165706c3fb27SDimitry Andric   llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
165806c3fb27SDimitry Andric                       const std::unique_ptr<Intrinsic> &B) {
165906c3fb27SDimitry Andric     return A->getMangledName() < B->getMangledName();
166006c3fb27SDimitry Andric   });
166106c3fb27SDimitry Andric 
166206c3fb27SDimitry Andric   OS << "#ifdef GET_SME_BUILTINS\n";
166306c3fb27SDimitry Andric   for (auto &Def : Defs) {
166406c3fb27SDimitry Andric     // Only create BUILTINs for non-overloaded intrinsics, as overloaded
166506c3fb27SDimitry Andric     // declarations only live in the header file.
1666*0fca6ea1SDimitry Andric     if (Def->getClassKind() != ClassG) {
166706c3fb27SDimitry Andric       OS << "TARGET_BUILTIN(__builtin_sme_" << Def->getMangledName() << ", \""
1668*0fca6ea1SDimitry Andric          << Def->getBuiltinTypeStr() << "\", \"n\", \"";
1669*0fca6ea1SDimitry Andric       Def->printGuard(OS);
1670*0fca6ea1SDimitry Andric       OS << "\")\n";
1671*0fca6ea1SDimitry Andric     }
167206c3fb27SDimitry Andric   }
167306c3fb27SDimitry Andric 
167406c3fb27SDimitry Andric   OS << "#endif\n\n";
167506c3fb27SDimitry Andric }
167606c3fb27SDimitry Andric 
167706c3fb27SDimitry Andric void SVEEmitter::createSMECodeGenMap(raw_ostream &OS) {
167806c3fb27SDimitry Andric   std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
167906c3fb27SDimitry Andric   SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
168006c3fb27SDimitry Andric   for (auto *R : RV) {
168106c3fb27SDimitry Andric     createIntrinsic(R, Defs);
168206c3fb27SDimitry Andric   }
168306c3fb27SDimitry Andric 
168406c3fb27SDimitry Andric   // The mappings must be sorted based on BuiltinID.
168506c3fb27SDimitry Andric   llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
168606c3fb27SDimitry Andric                       const std::unique_ptr<Intrinsic> &B) {
168706c3fb27SDimitry Andric     return A->getMangledName() < B->getMangledName();
168806c3fb27SDimitry Andric   });
168906c3fb27SDimitry Andric 
169006c3fb27SDimitry Andric   OS << "#ifdef GET_SME_LLVM_INTRINSIC_MAP\n";
169106c3fb27SDimitry Andric   for (auto &Def : Defs) {
169206c3fb27SDimitry Andric     // Builtins only exist for non-overloaded intrinsics, overloaded
169306c3fb27SDimitry Andric     // declarations only live in the header file.
169406c3fb27SDimitry Andric     if (Def->getClassKind() == ClassG)
169506c3fb27SDimitry Andric       continue;
169606c3fb27SDimitry Andric 
169706c3fb27SDimitry Andric     uint64_t Flags = Def->getFlags();
169806c3fb27SDimitry Andric     auto FlagString = std::to_string(Flags);
169906c3fb27SDimitry Andric 
170006c3fb27SDimitry Andric     std::string LLVMName = Def->getLLVMName();
170106c3fb27SDimitry Andric     std::string Builtin = Def->getMangledName();
170206c3fb27SDimitry Andric     if (!LLVMName.empty())
170306c3fb27SDimitry Andric       OS << "SMEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
170406c3fb27SDimitry Andric          << "),\n";
170506c3fb27SDimitry Andric     else
170606c3fb27SDimitry Andric       OS << "SMEMAP2(" << Builtin << ", " << FlagString << "),\n";
170706c3fb27SDimitry Andric   }
170806c3fb27SDimitry Andric   OS << "#endif\n\n";
170906c3fb27SDimitry Andric }
171006c3fb27SDimitry Andric 
171106c3fb27SDimitry Andric void SVEEmitter::createSMERangeChecks(raw_ostream &OS) {
171206c3fb27SDimitry Andric   std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
171306c3fb27SDimitry Andric   SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
171406c3fb27SDimitry Andric   for (auto *R : RV) {
171506c3fb27SDimitry Andric     createIntrinsic(R, Defs);
171606c3fb27SDimitry Andric   }
171706c3fb27SDimitry Andric 
171806c3fb27SDimitry Andric   // The mappings must be sorted based on BuiltinID.
171906c3fb27SDimitry Andric   llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
172006c3fb27SDimitry Andric                       const std::unique_ptr<Intrinsic> &B) {
172106c3fb27SDimitry Andric     return A->getMangledName() < B->getMangledName();
172206c3fb27SDimitry Andric   });
172306c3fb27SDimitry Andric 
172406c3fb27SDimitry Andric 
172506c3fb27SDimitry Andric   OS << "#ifdef GET_SME_IMMEDIATE_CHECK\n";
172606c3fb27SDimitry Andric 
172706c3fb27SDimitry Andric   // Ensure these are only emitted once.
172806c3fb27SDimitry Andric   std::set<std::string> Emitted;
172906c3fb27SDimitry Andric 
173006c3fb27SDimitry Andric   for (auto &Def : Defs) {
173106c3fb27SDimitry Andric     if (Emitted.find(Def->getMangledName()) != Emitted.end() ||
173206c3fb27SDimitry Andric         Def->getImmChecks().empty())
173306c3fb27SDimitry Andric       continue;
173406c3fb27SDimitry Andric 
173506c3fb27SDimitry Andric     OS << "case SME::BI__builtin_sme_" << Def->getMangledName() << ":\n";
173606c3fb27SDimitry Andric     for (auto &Check : Def->getImmChecks())
173706c3fb27SDimitry Andric       OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", "
173806c3fb27SDimitry Andric          << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n";
173906c3fb27SDimitry Andric     OS << "  break;\n";
174006c3fb27SDimitry Andric 
174106c3fb27SDimitry Andric     Emitted.insert(Def->getMangledName());
174206c3fb27SDimitry Andric   }
174306c3fb27SDimitry Andric 
174406c3fb27SDimitry Andric   OS << "#endif\n\n";
174506c3fb27SDimitry Andric }
174606c3fb27SDimitry Andric 
1747cb14a3feSDimitry Andric void SVEEmitter::createBuiltinZAState(raw_ostream &OS) {
1748cb14a3feSDimitry Andric   std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1749cb14a3feSDimitry Andric   SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1750cb14a3feSDimitry Andric   for (auto *R : RV)
1751cb14a3feSDimitry Andric     createIntrinsic(R, Defs);
1752cb14a3feSDimitry Andric 
17537a6dacacSDimitry Andric   std::map<std::string, std::set<std::string>> IntrinsicsPerState;
1754cb14a3feSDimitry Andric   for (auto &Def : Defs) {
17557a6dacacSDimitry Andric     std::string Key;
17567a6dacacSDimitry Andric     auto AddToKey = [&Key](const std::string &S) -> void {
17577a6dacacSDimitry Andric       Key = Key.empty() ? S : (Key + " | " + S);
17587a6dacacSDimitry Andric     };
17597a6dacacSDimitry Andric 
17607a6dacacSDimitry Andric     if (Def->isFlagSet(getEnumValueForFlag("IsInZA")))
17617a6dacacSDimitry Andric       AddToKey("ArmInZA");
17627a6dacacSDimitry Andric     else if (Def->isFlagSet(getEnumValueForFlag("IsOutZA")))
17637a6dacacSDimitry Andric       AddToKey("ArmOutZA");
17647a6dacacSDimitry Andric     else if (Def->isFlagSet(getEnumValueForFlag("IsInOutZA")))
17657a6dacacSDimitry Andric       AddToKey("ArmInOutZA");
17667a6dacacSDimitry Andric 
17677a6dacacSDimitry Andric     if (Def->isFlagSet(getEnumValueForFlag("IsInZT0")))
17687a6dacacSDimitry Andric       AddToKey("ArmInZT0");
17697a6dacacSDimitry Andric     else if (Def->isFlagSet(getEnumValueForFlag("IsOutZT0")))
17707a6dacacSDimitry Andric       AddToKey("ArmOutZT0");
17717a6dacacSDimitry Andric     else if (Def->isFlagSet(getEnumValueForFlag("IsInOutZT0")))
17727a6dacacSDimitry Andric       AddToKey("ArmInOutZT0");
17737a6dacacSDimitry Andric 
17747a6dacacSDimitry Andric     if (!Key.empty())
17757a6dacacSDimitry Andric       IntrinsicsPerState[Key].insert(Def->getMangledName());
1776cb14a3feSDimitry Andric   }
1777cb14a3feSDimitry Andric 
17787a6dacacSDimitry Andric   OS << "#ifdef GET_SME_BUILTIN_GET_STATE\n";
17797a6dacacSDimitry Andric   for (auto &KV : IntrinsicsPerState) {
17807a6dacacSDimitry Andric     for (StringRef Name : KV.second)
1781cb14a3feSDimitry Andric       OS << "case SME::BI__builtin_sme_" << Name << ":\n";
17827a6dacacSDimitry Andric     OS << "  return " << KV.first << ";\n";
1783cb14a3feSDimitry Andric   }
1784cb14a3feSDimitry Andric   OS << "#endif\n\n";
1785cb14a3feSDimitry Andric }
1786cb14a3feSDimitry Andric 
1787cb14a3feSDimitry Andric void SVEEmitter::createStreamingAttrs(raw_ostream &OS, ACLEKind Kind) {
1788cb14a3feSDimitry Andric   std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1789cb14a3feSDimitry Andric   SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1790cb14a3feSDimitry Andric   for (auto *R : RV)
1791cb14a3feSDimitry Andric     createIntrinsic(R, Defs);
1792cb14a3feSDimitry Andric 
1793cb14a3feSDimitry Andric   StringRef ExtensionKind;
1794cb14a3feSDimitry Andric   switch (Kind) {
1795cb14a3feSDimitry Andric   case ACLEKind::SME:
1796cb14a3feSDimitry Andric     ExtensionKind = "SME";
1797cb14a3feSDimitry Andric     break;
1798cb14a3feSDimitry Andric   case ACLEKind::SVE:
1799cb14a3feSDimitry Andric     ExtensionKind = "SVE";
1800cb14a3feSDimitry Andric     break;
1801cb14a3feSDimitry Andric   }
1802cb14a3feSDimitry Andric 
1803cb14a3feSDimitry Andric   OS << "#ifdef GET_" << ExtensionKind << "_STREAMING_ATTRS\n";
1804cb14a3feSDimitry Andric 
1805cb14a3feSDimitry Andric   llvm::StringMap<std::set<std::string>> StreamingMap;
1806cb14a3feSDimitry Andric 
1807cb14a3feSDimitry Andric   uint64_t IsStreamingFlag = getEnumValueForFlag("IsStreaming");
1808*0fca6ea1SDimitry Andric   uint64_t VerifyRuntimeMode = getEnumValueForFlag("VerifyRuntimeMode");
1809cb14a3feSDimitry Andric   uint64_t IsStreamingCompatibleFlag =
1810cb14a3feSDimitry Andric       getEnumValueForFlag("IsStreamingCompatible");
1811*0fca6ea1SDimitry Andric 
1812cb14a3feSDimitry Andric   for (auto &Def : Defs) {
1813*0fca6ea1SDimitry Andric     if (!Def->isFlagSet(VerifyRuntimeMode) && !Def->getSVEGuard().empty() &&
1814*0fca6ea1SDimitry Andric         !Def->getSMEGuard().empty())
1815*0fca6ea1SDimitry Andric       report_fatal_error("Missing VerifyRuntimeMode flag");
1816*0fca6ea1SDimitry Andric 
1817cb14a3feSDimitry Andric     if (Def->isFlagSet(IsStreamingFlag))
1818cb14a3feSDimitry Andric       StreamingMap["ArmStreaming"].insert(Def->getMangledName());
1819*0fca6ea1SDimitry Andric     else if (Def->isFlagSet(VerifyRuntimeMode))
1820*0fca6ea1SDimitry Andric       StreamingMap["VerifyRuntimeMode"].insert(Def->getMangledName());
1821cb14a3feSDimitry Andric     else if (Def->isFlagSet(IsStreamingCompatibleFlag))
1822cb14a3feSDimitry Andric       StreamingMap["ArmStreamingCompatible"].insert(Def->getMangledName());
1823cb14a3feSDimitry Andric     else
1824cb14a3feSDimitry Andric       StreamingMap["ArmNonStreaming"].insert(Def->getMangledName());
1825cb14a3feSDimitry Andric   }
1826cb14a3feSDimitry Andric 
1827cb14a3feSDimitry Andric   for (auto BuiltinType : StreamingMap.keys()) {
1828cb14a3feSDimitry Andric     for (auto Name : StreamingMap[BuiltinType]) {
1829cb14a3feSDimitry Andric       OS << "case " << ExtensionKind << "::BI__builtin_"
1830cb14a3feSDimitry Andric          << ExtensionKind.lower() << "_";
1831cb14a3feSDimitry Andric       OS << Name << ":\n";
1832cb14a3feSDimitry Andric     }
1833cb14a3feSDimitry Andric     OS << "  BuiltinType = " << BuiltinType << ";\n";
1834cb14a3feSDimitry Andric     OS << "  break;\n";
1835cb14a3feSDimitry Andric   }
1836cb14a3feSDimitry Andric 
1837cb14a3feSDimitry Andric   OS << "#endif\n\n";
1838cb14a3feSDimitry Andric }
1839cb14a3feSDimitry Andric 
18405ffd83dbSDimitry Andric namespace clang {
18415ffd83dbSDimitry Andric void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) {
18425ffd83dbSDimitry Andric   SVEEmitter(Records).createHeader(OS);
18435ffd83dbSDimitry Andric }
18445ffd83dbSDimitry Andric 
18455ffd83dbSDimitry Andric void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) {
18465ffd83dbSDimitry Andric   SVEEmitter(Records).createBuiltins(OS);
18475ffd83dbSDimitry Andric }
18485ffd83dbSDimitry Andric 
18495ffd83dbSDimitry Andric void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
18505ffd83dbSDimitry Andric   SVEEmitter(Records).createCodeGenMap(OS);
18515ffd83dbSDimitry Andric }
18525ffd83dbSDimitry Andric 
18535ffd83dbSDimitry Andric void EmitSveRangeChecks(RecordKeeper &Records, raw_ostream &OS) {
18545ffd83dbSDimitry Andric   SVEEmitter(Records).createRangeChecks(OS);
18555ffd83dbSDimitry Andric }
18565ffd83dbSDimitry Andric 
18575ffd83dbSDimitry Andric void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) {
18585ffd83dbSDimitry Andric   SVEEmitter(Records).createTypeFlags(OS);
18595ffd83dbSDimitry Andric }
18605ffd83dbSDimitry Andric 
1861cb14a3feSDimitry Andric void EmitSveStreamingAttrs(RecordKeeper &Records, raw_ostream &OS) {
1862cb14a3feSDimitry Andric   SVEEmitter(Records).createStreamingAttrs(OS, ACLEKind::SVE);
1863cb14a3feSDimitry Andric }
1864cb14a3feSDimitry Andric 
186506c3fb27SDimitry Andric void EmitSmeHeader(RecordKeeper &Records, raw_ostream &OS) {
186606c3fb27SDimitry Andric   SVEEmitter(Records).createSMEHeader(OS);
186706c3fb27SDimitry Andric }
186806c3fb27SDimitry Andric 
186906c3fb27SDimitry Andric void EmitSmeBuiltins(RecordKeeper &Records, raw_ostream &OS) {
187006c3fb27SDimitry Andric   SVEEmitter(Records).createSMEBuiltins(OS);
187106c3fb27SDimitry Andric }
187206c3fb27SDimitry Andric 
187306c3fb27SDimitry Andric void EmitSmeBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
187406c3fb27SDimitry Andric   SVEEmitter(Records).createSMECodeGenMap(OS);
187506c3fb27SDimitry Andric }
187606c3fb27SDimitry Andric 
187706c3fb27SDimitry Andric void EmitSmeRangeChecks(RecordKeeper &Records, raw_ostream &OS) {
187806c3fb27SDimitry Andric   SVEEmitter(Records).createSMERangeChecks(OS);
187906c3fb27SDimitry Andric }
18805f757f3fSDimitry Andric 
1881cb14a3feSDimitry Andric void EmitSmeStreamingAttrs(RecordKeeper &Records, raw_ostream &OS) {
1882cb14a3feSDimitry Andric   SVEEmitter(Records).createStreamingAttrs(OS, ACLEKind::SME);
1883cb14a3feSDimitry Andric }
1884cb14a3feSDimitry Andric 
1885cb14a3feSDimitry Andric void EmitSmeBuiltinZAState(RecordKeeper &Records, raw_ostream &OS) {
1886cb14a3feSDimitry Andric   SVEEmitter(Records).createBuiltinZAState(OS);
1887cb14a3feSDimitry Andric }
18885ffd83dbSDimitry Andric } // End namespace clang
1889