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