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/STLExtras.h" 275ffd83dbSDimitry Andric #include "llvm/ADT/StringMap.h" 285ffd83dbSDimitry Andric #include "llvm/ADT/ArrayRef.h" 295ffd83dbSDimitry Andric #include "llvm/ADT/StringExtras.h" 305ffd83dbSDimitry Andric #include "llvm/TableGen/Record.h" 315ffd83dbSDimitry Andric #include "llvm/TableGen/Error.h" 325ffd83dbSDimitry Andric #include <string> 335ffd83dbSDimitry Andric #include <sstream> 345ffd83dbSDimitry Andric #include <set> 355ffd83dbSDimitry Andric #include <cctype> 365ffd83dbSDimitry Andric #include <tuple> 375ffd83dbSDimitry Andric 385ffd83dbSDimitry Andric using namespace llvm; 395ffd83dbSDimitry Andric 405ffd83dbSDimitry Andric enum ClassKind { 415ffd83dbSDimitry Andric ClassNone, 425ffd83dbSDimitry Andric ClassS, // signed/unsigned, e.g., "_s8", "_u8" suffix 435ffd83dbSDimitry Andric ClassG, // Overloaded name without type suffix 445ffd83dbSDimitry Andric }; 455ffd83dbSDimitry Andric 465ffd83dbSDimitry Andric using TypeSpec = std::string; 475ffd83dbSDimitry Andric 485ffd83dbSDimitry Andric namespace { 495ffd83dbSDimitry Andric 505ffd83dbSDimitry Andric class ImmCheck { 515ffd83dbSDimitry Andric unsigned Arg; 525ffd83dbSDimitry Andric unsigned Kind; 535ffd83dbSDimitry Andric unsigned ElementSizeInBits; 545ffd83dbSDimitry Andric 555ffd83dbSDimitry Andric public: 565ffd83dbSDimitry Andric ImmCheck(unsigned Arg, unsigned Kind, unsigned ElementSizeInBits = 0) 575ffd83dbSDimitry Andric : Arg(Arg), Kind(Kind), ElementSizeInBits(ElementSizeInBits) {} 585ffd83dbSDimitry Andric ImmCheck(const ImmCheck &Other) = default; 595ffd83dbSDimitry Andric ~ImmCheck() = default; 605ffd83dbSDimitry Andric 615ffd83dbSDimitry Andric unsigned getArg() const { return Arg; } 625ffd83dbSDimitry Andric unsigned getKind() const { return Kind; } 635ffd83dbSDimitry Andric unsigned getElementSizeInBits() const { return ElementSizeInBits; } 645ffd83dbSDimitry Andric }; 655ffd83dbSDimitry Andric 665ffd83dbSDimitry Andric class SVEType { 675ffd83dbSDimitry Andric TypeSpec TS; 685ffd83dbSDimitry Andric bool Float, Signed, Immediate, Void, Constant, Pointer, BFloat; 69*06c3fb27SDimitry Andric bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp, 70*06c3fb27SDimitry Andric Svcount; 715ffd83dbSDimitry Andric unsigned Bitwidth, ElementBitwidth, NumVectors; 725ffd83dbSDimitry Andric 735ffd83dbSDimitry Andric public: 745ffd83dbSDimitry Andric SVEType() : SVEType(TypeSpec(), 'v') {} 755ffd83dbSDimitry Andric 765ffd83dbSDimitry Andric SVEType(TypeSpec TS, char CharMod) 775ffd83dbSDimitry Andric : TS(TS), Float(false), Signed(true), Immediate(false), Void(false), 785ffd83dbSDimitry Andric Constant(false), Pointer(false), BFloat(false), DefaultType(false), 795ffd83dbSDimitry Andric IsScalable(true), Predicate(false), PredicatePattern(false), 80*06c3fb27SDimitry Andric PrefetchOp(false), Svcount(false), Bitwidth(128), ElementBitwidth(~0U), 81*06c3fb27SDimitry Andric NumVectors(1) { 825ffd83dbSDimitry Andric if (!TS.empty()) 835ffd83dbSDimitry Andric applyTypespec(); 845ffd83dbSDimitry Andric applyModifier(CharMod); 855ffd83dbSDimitry Andric } 865ffd83dbSDimitry Andric 875ffd83dbSDimitry Andric bool isPointer() const { return Pointer; } 885ffd83dbSDimitry Andric bool isVoidPointer() const { return Pointer && Void; } 895ffd83dbSDimitry Andric bool isSigned() const { return Signed; } 905ffd83dbSDimitry Andric bool isImmediate() const { return Immediate; } 915ffd83dbSDimitry Andric bool isScalar() const { return NumVectors == 0; } 925ffd83dbSDimitry Andric bool isVector() const { return NumVectors > 0; } 935ffd83dbSDimitry Andric bool isScalableVector() const { return isVector() && IsScalable; } 945ffd83dbSDimitry Andric bool isChar() const { return ElementBitwidth == 8; } 955ffd83dbSDimitry Andric bool isVoid() const { return Void & !Pointer; } 965ffd83dbSDimitry Andric bool isDefault() const { return DefaultType; } 975ffd83dbSDimitry Andric bool isFloat() const { return Float && !BFloat; } 985ffd83dbSDimitry Andric bool isBFloat() const { return BFloat && !Float; } 995ffd83dbSDimitry Andric bool isFloatingPoint() const { return Float || BFloat; } 100*06c3fb27SDimitry Andric bool isInteger() const { 101*06c3fb27SDimitry Andric return !isFloatingPoint() && !Predicate && !Svcount; 102*06c3fb27SDimitry Andric } 1035ffd83dbSDimitry Andric bool isScalarPredicate() const { 1045ffd83dbSDimitry Andric return !isFloatingPoint() && Predicate && NumVectors == 0; 1055ffd83dbSDimitry Andric } 1065ffd83dbSDimitry Andric bool isPredicateVector() const { return Predicate; } 1075ffd83dbSDimitry Andric bool isPredicatePattern() const { return PredicatePattern; } 1085ffd83dbSDimitry Andric bool isPrefetchOp() const { return PrefetchOp; } 109*06c3fb27SDimitry Andric bool isSvcount() const { return Svcount; } 1105ffd83dbSDimitry Andric bool isConstant() const { return Constant; } 1115ffd83dbSDimitry Andric unsigned getElementSizeInBits() const { return ElementBitwidth; } 1125ffd83dbSDimitry Andric unsigned getNumVectors() const { return NumVectors; } 1135ffd83dbSDimitry Andric 1145ffd83dbSDimitry Andric unsigned getNumElements() const { 1155ffd83dbSDimitry Andric assert(ElementBitwidth != ~0U); 1165ffd83dbSDimitry Andric return Bitwidth / ElementBitwidth; 1175ffd83dbSDimitry Andric } 1185ffd83dbSDimitry Andric unsigned getSizeInBits() const { 1195ffd83dbSDimitry Andric return Bitwidth; 1205ffd83dbSDimitry Andric } 1215ffd83dbSDimitry Andric 1225ffd83dbSDimitry Andric /// Return the string representation of a type, which is an encoded 1235ffd83dbSDimitry Andric /// string for passing to the BUILTIN() macro in Builtins.def. 1245ffd83dbSDimitry Andric std::string builtin_str() const; 1255ffd83dbSDimitry Andric 1265ffd83dbSDimitry Andric /// Return the C/C++ string representation of a type for use in the 1275ffd83dbSDimitry Andric /// arm_sve.h header file. 1285ffd83dbSDimitry Andric std::string str() const; 1295ffd83dbSDimitry Andric 1305ffd83dbSDimitry Andric private: 1315ffd83dbSDimitry Andric /// Creates the type based on the typespec string in TS. 1325ffd83dbSDimitry Andric void applyTypespec(); 1335ffd83dbSDimitry Andric 1345ffd83dbSDimitry Andric /// Applies a prototype modifier to the type. 1355ffd83dbSDimitry Andric void applyModifier(char Mod); 1365ffd83dbSDimitry Andric }; 1375ffd83dbSDimitry Andric 1385ffd83dbSDimitry Andric 1395ffd83dbSDimitry Andric class SVEEmitter; 1405ffd83dbSDimitry Andric 1415ffd83dbSDimitry Andric /// The main grunt class. This represents an instantiation of an intrinsic with 1425ffd83dbSDimitry Andric /// a particular typespec and prototype. 1435ffd83dbSDimitry Andric class Intrinsic { 1445ffd83dbSDimitry Andric /// The unmangled name. 1455ffd83dbSDimitry Andric std::string Name; 1465ffd83dbSDimitry Andric 1475ffd83dbSDimitry Andric /// The name of the corresponding LLVM IR intrinsic. 1485ffd83dbSDimitry Andric std::string LLVMName; 1495ffd83dbSDimitry Andric 1505ffd83dbSDimitry Andric /// Intrinsic prototype. 1515ffd83dbSDimitry Andric std::string Proto; 1525ffd83dbSDimitry Andric 1535ffd83dbSDimitry Andric /// The base type spec for this intrinsic. 1545ffd83dbSDimitry Andric TypeSpec BaseTypeSpec; 1555ffd83dbSDimitry Andric 1565ffd83dbSDimitry Andric /// The base class kind. Most intrinsics use ClassS, which has full type 1575ffd83dbSDimitry Andric /// info for integers (_s32/_u32), or ClassG which is used for overloaded 1585ffd83dbSDimitry Andric /// intrinsics. 1595ffd83dbSDimitry Andric ClassKind Class; 1605ffd83dbSDimitry Andric 1615ffd83dbSDimitry Andric /// The architectural #ifdef guard. 1625ffd83dbSDimitry Andric std::string Guard; 1635ffd83dbSDimitry Andric 1645ffd83dbSDimitry Andric // The merge suffix such as _m, _x or _z. 1655ffd83dbSDimitry Andric std::string MergeSuffix; 1665ffd83dbSDimitry Andric 1675ffd83dbSDimitry Andric /// The types of return value [0] and parameters [1..]. 1685ffd83dbSDimitry Andric std::vector<SVEType> Types; 1695ffd83dbSDimitry Andric 1705ffd83dbSDimitry Andric /// The "base type", which is VarType('d', BaseTypeSpec). 1715ffd83dbSDimitry Andric SVEType BaseType; 1725ffd83dbSDimitry Andric 1735ffd83dbSDimitry Andric uint64_t Flags; 1745ffd83dbSDimitry Andric 1755ffd83dbSDimitry Andric SmallVector<ImmCheck, 2> ImmChecks; 1765ffd83dbSDimitry Andric 1775ffd83dbSDimitry Andric public: 1785ffd83dbSDimitry Andric Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy, 1795ffd83dbSDimitry Andric StringRef MergeSuffix, uint64_t MemoryElementTy, StringRef LLVMName, 1805ffd83dbSDimitry Andric uint64_t Flags, ArrayRef<ImmCheck> ImmChecks, TypeSpec BT, 1815ffd83dbSDimitry Andric ClassKind Class, SVEEmitter &Emitter, StringRef Guard); 1825ffd83dbSDimitry Andric 1835ffd83dbSDimitry Andric ~Intrinsic()=default; 1845ffd83dbSDimitry Andric 1855ffd83dbSDimitry Andric std::string getName() const { return Name; } 1865ffd83dbSDimitry Andric std::string getLLVMName() const { return LLVMName; } 1875ffd83dbSDimitry Andric std::string getProto() const { return Proto; } 1885ffd83dbSDimitry Andric TypeSpec getBaseTypeSpec() const { return BaseTypeSpec; } 1895ffd83dbSDimitry Andric SVEType getBaseType() const { return BaseType; } 1905ffd83dbSDimitry Andric 1915ffd83dbSDimitry Andric StringRef getGuard() const { return Guard; } 1925ffd83dbSDimitry Andric ClassKind getClassKind() const { return Class; } 1935ffd83dbSDimitry Andric 1945ffd83dbSDimitry Andric SVEType getReturnType() const { return Types[0]; } 1955ffd83dbSDimitry Andric ArrayRef<SVEType> getTypes() const { return Types; } 1965ffd83dbSDimitry Andric SVEType getParamType(unsigned I) const { return Types[I + 1]; } 1975ffd83dbSDimitry Andric unsigned getNumParams() const { return Proto.size() - 1; } 1985ffd83dbSDimitry Andric 1995ffd83dbSDimitry Andric uint64_t getFlags() const { return Flags; } 2005ffd83dbSDimitry Andric bool isFlagSet(uint64_t Flag) const { return Flags & Flag;} 2015ffd83dbSDimitry Andric 2025ffd83dbSDimitry Andric ArrayRef<ImmCheck> getImmChecks() const { return ImmChecks; } 2035ffd83dbSDimitry Andric 2045ffd83dbSDimitry Andric /// Return the type string for a BUILTIN() macro in Builtins.def. 2055ffd83dbSDimitry Andric std::string getBuiltinTypeStr(); 2065ffd83dbSDimitry Andric 2075ffd83dbSDimitry Andric /// Return the name, mangled with type information. The name is mangled for 2085ffd83dbSDimitry Andric /// ClassS, so will add type suffixes such as _u32/_s32. 2095ffd83dbSDimitry Andric std::string getMangledName() const { return mangleName(ClassS); } 2105ffd83dbSDimitry Andric 211*06c3fb27SDimitry Andric /// As above, but mangles the LLVM name instead. 212*06c3fb27SDimitry Andric std::string getMangledLLVMName() const { return mangleLLVMName(); } 213*06c3fb27SDimitry Andric 2145ffd83dbSDimitry Andric /// Returns true if the intrinsic is overloaded, in that it should also generate 2155ffd83dbSDimitry Andric /// a short form without the type-specifiers, e.g. 'svld1(..)' instead of 2165ffd83dbSDimitry Andric /// 'svld1_u32(..)'. 2175ffd83dbSDimitry Andric static bool isOverloadedIntrinsic(StringRef Name) { 218e8d8bef9SDimitry Andric auto BrOpen = Name.find('['); 2195ffd83dbSDimitry Andric auto BrClose = Name.find(']'); 2205ffd83dbSDimitry Andric return BrOpen != std::string::npos && BrClose != std::string::npos; 2215ffd83dbSDimitry Andric } 2225ffd83dbSDimitry Andric 2235ffd83dbSDimitry Andric /// Return true if the intrinsic takes a splat operand. 2245ffd83dbSDimitry Andric bool hasSplat() const { 2255ffd83dbSDimitry Andric // These prototype modifiers are described in arm_sve.td. 2265ffd83dbSDimitry Andric return Proto.find_first_of("ajfrKLR@") != std::string::npos; 2275ffd83dbSDimitry Andric } 2285ffd83dbSDimitry Andric 2295ffd83dbSDimitry Andric /// Return the parameter index of the splat operand. 2305ffd83dbSDimitry Andric unsigned getSplatIdx() const { 2315ffd83dbSDimitry Andric // These prototype modifiers are described in arm_sve.td. 2325ffd83dbSDimitry Andric auto Idx = Proto.find_first_of("ajfrKLR@"); 2335ffd83dbSDimitry Andric assert(Idx != std::string::npos && Idx > 0 && 2345ffd83dbSDimitry Andric "Prototype has no splat operand"); 2355ffd83dbSDimitry Andric return Idx - 1; 2365ffd83dbSDimitry Andric } 2375ffd83dbSDimitry Andric 2385ffd83dbSDimitry Andric /// Emits the intrinsic declaration to the ostream. 239*06c3fb27SDimitry Andric void emitIntrinsic(raw_ostream &OS, SVEEmitter &Emitter) const; 2405ffd83dbSDimitry Andric 2415ffd83dbSDimitry Andric private: 2425ffd83dbSDimitry Andric std::string getMergeSuffix() const { return MergeSuffix; } 2435ffd83dbSDimitry Andric std::string mangleName(ClassKind LocalCK) const; 244*06c3fb27SDimitry Andric std::string mangleLLVMName() const; 2455ffd83dbSDimitry Andric std::string replaceTemplatedArgs(std::string Name, TypeSpec TS, 2465ffd83dbSDimitry Andric std::string Proto) const; 2475ffd83dbSDimitry Andric }; 2485ffd83dbSDimitry Andric 2495ffd83dbSDimitry Andric class SVEEmitter { 2505ffd83dbSDimitry Andric private: 2515ffd83dbSDimitry Andric // The reinterpret builtins are generated separately because they 2525ffd83dbSDimitry Andric // need the cross product of all types (121 functions in total), 2535ffd83dbSDimitry Andric // which is inconvenient to specify in the arm_sve.td file or 2545ffd83dbSDimitry Andric // generate in CGBuiltin.cpp. 2555ffd83dbSDimitry Andric struct ReinterpretTypeInfo { 2565ffd83dbSDimitry Andric const char *Suffix; 2575ffd83dbSDimitry Andric const char *Type; 2585ffd83dbSDimitry Andric const char *BuiltinType; 2595ffd83dbSDimitry Andric }; 2605ffd83dbSDimitry Andric SmallVector<ReinterpretTypeInfo, 12> Reinterprets = { 2615ffd83dbSDimitry Andric {"s8", "svint8_t", "q16Sc"}, {"s16", "svint16_t", "q8Ss"}, 2625ffd83dbSDimitry Andric {"s32", "svint32_t", "q4Si"}, {"s64", "svint64_t", "q2SWi"}, 2635ffd83dbSDimitry Andric {"u8", "svuint8_t", "q16Uc"}, {"u16", "svuint16_t", "q8Us"}, 2645ffd83dbSDimitry Andric {"u32", "svuint32_t", "q4Ui"}, {"u64", "svuint64_t", "q2UWi"}, 2655ffd83dbSDimitry Andric {"f16", "svfloat16_t", "q8h"}, {"bf16", "svbfloat16_t", "q8y"}, 2665ffd83dbSDimitry Andric {"f32", "svfloat32_t", "q4f"}, {"f64", "svfloat64_t", "q2d"}}; 2675ffd83dbSDimitry Andric 2685ffd83dbSDimitry Andric RecordKeeper &Records; 2695ffd83dbSDimitry Andric llvm::StringMap<uint64_t> EltTypes; 2705ffd83dbSDimitry Andric llvm::StringMap<uint64_t> MemEltTypes; 2715ffd83dbSDimitry Andric llvm::StringMap<uint64_t> FlagTypes; 2725ffd83dbSDimitry Andric llvm::StringMap<uint64_t> MergeTypes; 2735ffd83dbSDimitry Andric llvm::StringMap<uint64_t> ImmCheckTypes; 2745ffd83dbSDimitry Andric 2755ffd83dbSDimitry Andric public: 2765ffd83dbSDimitry Andric SVEEmitter(RecordKeeper &R) : Records(R) { 2775ffd83dbSDimitry Andric for (auto *RV : Records.getAllDerivedDefinitions("EltType")) 2785ffd83dbSDimitry Andric EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 2795ffd83dbSDimitry Andric for (auto *RV : Records.getAllDerivedDefinitions("MemEltType")) 2805ffd83dbSDimitry Andric MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 2815ffd83dbSDimitry Andric for (auto *RV : Records.getAllDerivedDefinitions("FlagType")) 2825ffd83dbSDimitry Andric FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 2835ffd83dbSDimitry Andric for (auto *RV : Records.getAllDerivedDefinitions("MergeType")) 2845ffd83dbSDimitry Andric MergeTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 2855ffd83dbSDimitry Andric for (auto *RV : Records.getAllDerivedDefinitions("ImmCheckType")) 2865ffd83dbSDimitry Andric ImmCheckTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 2875ffd83dbSDimitry Andric } 2885ffd83dbSDimitry Andric 2895ffd83dbSDimitry Andric /// Returns the enum value for the immcheck type 2905ffd83dbSDimitry Andric unsigned getEnumValueForImmCheck(StringRef C) const { 2915ffd83dbSDimitry Andric auto It = ImmCheckTypes.find(C); 2925ffd83dbSDimitry Andric if (It != ImmCheckTypes.end()) 2935ffd83dbSDimitry Andric return It->getValue(); 2945ffd83dbSDimitry Andric llvm_unreachable("Unsupported imm check"); 2955ffd83dbSDimitry Andric } 2965ffd83dbSDimitry Andric 2975ffd83dbSDimitry Andric /// Returns the enum value for the flag type 2985ffd83dbSDimitry Andric uint64_t getEnumValueForFlag(StringRef C) const { 2995ffd83dbSDimitry Andric auto Res = FlagTypes.find(C); 3005ffd83dbSDimitry Andric if (Res != FlagTypes.end()) 3015ffd83dbSDimitry Andric return Res->getValue(); 3025ffd83dbSDimitry Andric llvm_unreachable("Unsupported flag"); 3035ffd83dbSDimitry Andric } 3045ffd83dbSDimitry Andric 3055ffd83dbSDimitry Andric // Returns the SVETypeFlags for a given value and mask. 3065ffd83dbSDimitry Andric uint64_t encodeFlag(uint64_t V, StringRef MaskName) const { 3075ffd83dbSDimitry Andric auto It = FlagTypes.find(MaskName); 3085ffd83dbSDimitry Andric if (It != FlagTypes.end()) { 3095ffd83dbSDimitry Andric uint64_t Mask = It->getValue(); 310*06c3fb27SDimitry Andric unsigned Shift = llvm::countr_zero(Mask); 311*06c3fb27SDimitry Andric assert(Shift < 64 && "Mask value produced an invalid shift value"); 3125ffd83dbSDimitry Andric return (V << Shift) & Mask; 3135ffd83dbSDimitry Andric } 3145ffd83dbSDimitry Andric llvm_unreachable("Unsupported flag"); 3155ffd83dbSDimitry Andric } 3165ffd83dbSDimitry Andric 3175ffd83dbSDimitry Andric // Returns the SVETypeFlags for the given element type. 3185ffd83dbSDimitry Andric uint64_t encodeEltType(StringRef EltName) { 3195ffd83dbSDimitry Andric auto It = EltTypes.find(EltName); 3205ffd83dbSDimitry Andric if (It != EltTypes.end()) 3215ffd83dbSDimitry Andric return encodeFlag(It->getValue(), "EltTypeMask"); 3225ffd83dbSDimitry Andric llvm_unreachable("Unsupported EltType"); 3235ffd83dbSDimitry Andric } 3245ffd83dbSDimitry Andric 3255ffd83dbSDimitry Andric // Returns the SVETypeFlags for the given memory element type. 3265ffd83dbSDimitry Andric uint64_t encodeMemoryElementType(uint64_t MT) { 3275ffd83dbSDimitry Andric return encodeFlag(MT, "MemEltTypeMask"); 3285ffd83dbSDimitry Andric } 3295ffd83dbSDimitry Andric 3305ffd83dbSDimitry Andric // Returns the SVETypeFlags for the given merge type. 3315ffd83dbSDimitry Andric uint64_t encodeMergeType(uint64_t MT) { 3325ffd83dbSDimitry Andric return encodeFlag(MT, "MergeTypeMask"); 3335ffd83dbSDimitry Andric } 3345ffd83dbSDimitry Andric 3355ffd83dbSDimitry Andric // Returns the SVETypeFlags for the given splat operand. 3365ffd83dbSDimitry Andric unsigned encodeSplatOperand(unsigned SplatIdx) { 3375ffd83dbSDimitry Andric assert(SplatIdx < 7 && "SplatIdx out of encodable range"); 3385ffd83dbSDimitry Andric return encodeFlag(SplatIdx + 1, "SplatOperandMask"); 3395ffd83dbSDimitry Andric } 3405ffd83dbSDimitry Andric 3415ffd83dbSDimitry Andric // Returns the SVETypeFlags value for the given SVEType. 3425ffd83dbSDimitry Andric uint64_t encodeTypeFlags(const SVEType &T); 3435ffd83dbSDimitry Andric 3445ffd83dbSDimitry Andric /// Emit arm_sve.h. 3455ffd83dbSDimitry Andric void createHeader(raw_ostream &o); 3465ffd83dbSDimitry Andric 3475ffd83dbSDimitry Andric /// Emit all the __builtin prototypes and code needed by Sema. 3485ffd83dbSDimitry Andric void createBuiltins(raw_ostream &o); 3495ffd83dbSDimitry Andric 3505ffd83dbSDimitry Andric /// Emit all the information needed to map builtin -> LLVM IR intrinsic. 3515ffd83dbSDimitry Andric void createCodeGenMap(raw_ostream &o); 3525ffd83dbSDimitry Andric 3535ffd83dbSDimitry Andric /// Emit all the range checks for the immediates. 3545ffd83dbSDimitry Andric void createRangeChecks(raw_ostream &o); 3555ffd83dbSDimitry Andric 3565ffd83dbSDimitry Andric /// Create the SVETypeFlags used in CGBuiltins 3575ffd83dbSDimitry Andric void createTypeFlags(raw_ostream &o); 3585ffd83dbSDimitry Andric 359*06c3fb27SDimitry Andric /// Emit arm_sme.h. 360*06c3fb27SDimitry Andric void createSMEHeader(raw_ostream &o); 361*06c3fb27SDimitry Andric 362*06c3fb27SDimitry Andric /// Emit all the SME __builtin prototypes and code needed by Sema. 363*06c3fb27SDimitry Andric void createSMEBuiltins(raw_ostream &o); 364*06c3fb27SDimitry Andric 365*06c3fb27SDimitry Andric /// Emit all the information needed to map builtin -> LLVM IR intrinsic. 366*06c3fb27SDimitry Andric void createSMECodeGenMap(raw_ostream &o); 367*06c3fb27SDimitry Andric 368*06c3fb27SDimitry Andric /// Emit all the range checks for the immediates. 369*06c3fb27SDimitry Andric void createSMERangeChecks(raw_ostream &o); 370*06c3fb27SDimitry Andric 3715ffd83dbSDimitry Andric /// Create intrinsic and add it to \p Out 372*06c3fb27SDimitry Andric void createIntrinsic(Record *R, 373*06c3fb27SDimitry Andric SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out); 3745ffd83dbSDimitry Andric }; 3755ffd83dbSDimitry Andric 3765ffd83dbSDimitry Andric } // end anonymous namespace 3775ffd83dbSDimitry Andric 3785ffd83dbSDimitry Andric 3795ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 3805ffd83dbSDimitry Andric // Type implementation 3815ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 3825ffd83dbSDimitry Andric 3835ffd83dbSDimitry Andric std::string SVEType::builtin_str() const { 3845ffd83dbSDimitry Andric std::string S; 3855ffd83dbSDimitry Andric if (isVoid()) 3865ffd83dbSDimitry Andric return "v"; 3875ffd83dbSDimitry Andric 388fe6060f1SDimitry Andric if (isScalarPredicate()) 389fe6060f1SDimitry Andric return "b"; 390fe6060f1SDimitry Andric 391*06c3fb27SDimitry Andric if (isSvcount()) 392*06c3fb27SDimitry Andric return "Qa"; 393*06c3fb27SDimitry Andric 3945ffd83dbSDimitry Andric if (isVoidPointer()) 3955ffd83dbSDimitry Andric S += "v"; 3965ffd83dbSDimitry Andric else if (!isFloatingPoint()) 3975ffd83dbSDimitry Andric switch (ElementBitwidth) { 3985ffd83dbSDimitry Andric case 1: S += "b"; break; 3995ffd83dbSDimitry Andric case 8: S += "c"; break; 4005ffd83dbSDimitry Andric case 16: S += "s"; break; 4015ffd83dbSDimitry Andric case 32: S += "i"; break; 4025ffd83dbSDimitry Andric case 64: S += "Wi"; break; 4035ffd83dbSDimitry Andric case 128: S += "LLLi"; break; 4045ffd83dbSDimitry Andric default: llvm_unreachable("Unhandled case!"); 4055ffd83dbSDimitry Andric } 4065ffd83dbSDimitry Andric else if (isFloat()) 4075ffd83dbSDimitry Andric switch (ElementBitwidth) { 4085ffd83dbSDimitry Andric case 16: S += "h"; break; 4095ffd83dbSDimitry Andric case 32: S += "f"; break; 4105ffd83dbSDimitry Andric case 64: S += "d"; break; 4115ffd83dbSDimitry Andric default: llvm_unreachable("Unhandled case!"); 4125ffd83dbSDimitry Andric } 4135ffd83dbSDimitry Andric else if (isBFloat()) { 4145ffd83dbSDimitry Andric assert(ElementBitwidth == 16 && "Not a valid BFloat."); 4155ffd83dbSDimitry Andric S += "y"; 4165ffd83dbSDimitry Andric } 4175ffd83dbSDimitry Andric 4185ffd83dbSDimitry Andric if (!isFloatingPoint()) { 4195ffd83dbSDimitry Andric if ((isChar() || isPointer()) && !isVoidPointer()) { 4205ffd83dbSDimitry Andric // Make chars and typed pointers explicitly signed. 4215ffd83dbSDimitry Andric if (Signed) 4225ffd83dbSDimitry Andric S = "S" + S; 4235ffd83dbSDimitry Andric else if (!Signed) 4245ffd83dbSDimitry Andric S = "U" + S; 4255ffd83dbSDimitry Andric } else if (!isVoidPointer() && !Signed) { 4265ffd83dbSDimitry Andric S = "U" + S; 4275ffd83dbSDimitry Andric } 4285ffd83dbSDimitry Andric } 4295ffd83dbSDimitry Andric 4305ffd83dbSDimitry Andric // Constant indices are "int", but have the "constant expression" modifier. 4315ffd83dbSDimitry Andric if (isImmediate()) { 4325ffd83dbSDimitry Andric assert(!isFloat() && "fp immediates are not supported"); 4335ffd83dbSDimitry Andric S = "I" + S; 4345ffd83dbSDimitry Andric } 4355ffd83dbSDimitry Andric 4365ffd83dbSDimitry Andric if (isScalar()) { 4375ffd83dbSDimitry Andric if (Constant) S += "C"; 4385ffd83dbSDimitry Andric if (Pointer) S += "*"; 4395ffd83dbSDimitry Andric return S; 4405ffd83dbSDimitry Andric } 4415ffd83dbSDimitry Andric 4425ffd83dbSDimitry Andric assert(isScalableVector() && "Unsupported type"); 4435ffd83dbSDimitry Andric return "q" + utostr(getNumElements() * NumVectors) + S; 4445ffd83dbSDimitry Andric } 4455ffd83dbSDimitry Andric 4465ffd83dbSDimitry Andric std::string SVEType::str() const { 4475ffd83dbSDimitry Andric if (isPredicatePattern()) 448e8d8bef9SDimitry Andric return "enum svpattern"; 4495ffd83dbSDimitry Andric 4505ffd83dbSDimitry Andric if (isPrefetchOp()) 451e8d8bef9SDimitry Andric return "enum svprfop"; 4525ffd83dbSDimitry Andric 4535ffd83dbSDimitry Andric std::string S; 4545ffd83dbSDimitry Andric if (Void) 4555ffd83dbSDimitry Andric S += "void"; 4565ffd83dbSDimitry Andric else { 457*06c3fb27SDimitry Andric if (isScalableVector() || isSvcount()) 4585ffd83dbSDimitry Andric S += "sv"; 4595ffd83dbSDimitry Andric if (!Signed && !isFloatingPoint()) 4605ffd83dbSDimitry Andric S += "u"; 4615ffd83dbSDimitry Andric 4625ffd83dbSDimitry Andric if (Float) 4635ffd83dbSDimitry Andric S += "float"; 464*06c3fb27SDimitry Andric else if (isSvcount()) 465*06c3fb27SDimitry Andric S += "count"; 4665ffd83dbSDimitry Andric else if (isScalarPredicate() || isPredicateVector()) 4675ffd83dbSDimitry Andric S += "bool"; 4685ffd83dbSDimitry Andric else if (isBFloat()) 4695ffd83dbSDimitry Andric S += "bfloat"; 4705ffd83dbSDimitry Andric else 4715ffd83dbSDimitry Andric S += "int"; 4725ffd83dbSDimitry Andric 473*06c3fb27SDimitry Andric if (!isScalarPredicate() && !isPredicateVector() && !isSvcount()) 4745ffd83dbSDimitry Andric S += utostr(ElementBitwidth); 4755ffd83dbSDimitry Andric if (!isScalableVector() && isVector()) 4765ffd83dbSDimitry Andric S += "x" + utostr(getNumElements()); 4775ffd83dbSDimitry Andric if (NumVectors > 1) 4785ffd83dbSDimitry Andric S += "x" + utostr(NumVectors); 4795ffd83dbSDimitry Andric if (!isScalarPredicate()) 4805ffd83dbSDimitry Andric S += "_t"; 4815ffd83dbSDimitry Andric } 4825ffd83dbSDimitry Andric 4835ffd83dbSDimitry Andric if (Constant) 4845ffd83dbSDimitry Andric S += " const"; 4855ffd83dbSDimitry Andric if (Pointer) 4865ffd83dbSDimitry Andric S += " *"; 4875ffd83dbSDimitry Andric 4885ffd83dbSDimitry Andric return S; 4895ffd83dbSDimitry Andric } 4905ffd83dbSDimitry Andric void SVEType::applyTypespec() { 4915ffd83dbSDimitry Andric for (char I : TS) { 4925ffd83dbSDimitry Andric switch (I) { 493*06c3fb27SDimitry Andric case 'Q': 494*06c3fb27SDimitry Andric Svcount = true; 495*06c3fb27SDimitry Andric break; 4965ffd83dbSDimitry Andric case 'P': 4975ffd83dbSDimitry Andric Predicate = true; 4985ffd83dbSDimitry Andric break; 4995ffd83dbSDimitry Andric case 'U': 5005ffd83dbSDimitry Andric Signed = false; 5015ffd83dbSDimitry Andric break; 5025ffd83dbSDimitry Andric case 'c': 5035ffd83dbSDimitry Andric ElementBitwidth = 8; 5045ffd83dbSDimitry Andric break; 5055ffd83dbSDimitry Andric case 's': 5065ffd83dbSDimitry Andric ElementBitwidth = 16; 5075ffd83dbSDimitry Andric break; 5085ffd83dbSDimitry Andric case 'i': 5095ffd83dbSDimitry Andric ElementBitwidth = 32; 5105ffd83dbSDimitry Andric break; 5115ffd83dbSDimitry Andric case 'l': 5125ffd83dbSDimitry Andric ElementBitwidth = 64; 5135ffd83dbSDimitry Andric break; 514*06c3fb27SDimitry Andric case 'q': 515*06c3fb27SDimitry Andric ElementBitwidth = 128; 516*06c3fb27SDimitry Andric break; 5175ffd83dbSDimitry Andric case 'h': 5185ffd83dbSDimitry Andric Float = true; 5195ffd83dbSDimitry Andric ElementBitwidth = 16; 5205ffd83dbSDimitry Andric break; 5215ffd83dbSDimitry Andric case 'f': 5225ffd83dbSDimitry Andric Float = true; 5235ffd83dbSDimitry Andric ElementBitwidth = 32; 5245ffd83dbSDimitry Andric break; 5255ffd83dbSDimitry Andric case 'd': 5265ffd83dbSDimitry Andric Float = true; 5275ffd83dbSDimitry Andric ElementBitwidth = 64; 5285ffd83dbSDimitry Andric break; 5295ffd83dbSDimitry Andric case 'b': 5305ffd83dbSDimitry Andric BFloat = true; 5315ffd83dbSDimitry Andric Float = false; 5325ffd83dbSDimitry Andric ElementBitwidth = 16; 5335ffd83dbSDimitry Andric break; 5345ffd83dbSDimitry Andric default: 5355ffd83dbSDimitry Andric llvm_unreachable("Unhandled type code!"); 5365ffd83dbSDimitry Andric } 5375ffd83dbSDimitry Andric } 5385ffd83dbSDimitry Andric assert(ElementBitwidth != ~0U && "Bad element bitwidth!"); 5395ffd83dbSDimitry Andric } 5405ffd83dbSDimitry Andric 5415ffd83dbSDimitry Andric void SVEType::applyModifier(char Mod) { 5425ffd83dbSDimitry Andric switch (Mod) { 5435ffd83dbSDimitry Andric case '2': 5445ffd83dbSDimitry Andric NumVectors = 2; 5455ffd83dbSDimitry Andric break; 5465ffd83dbSDimitry Andric case '3': 5475ffd83dbSDimitry Andric NumVectors = 3; 5485ffd83dbSDimitry Andric break; 5495ffd83dbSDimitry Andric case '4': 5505ffd83dbSDimitry Andric NumVectors = 4; 5515ffd83dbSDimitry Andric break; 5525ffd83dbSDimitry Andric case 'v': 5535ffd83dbSDimitry Andric Void = true; 5545ffd83dbSDimitry Andric break; 5555ffd83dbSDimitry Andric case 'd': 5565ffd83dbSDimitry Andric DefaultType = true; 5575ffd83dbSDimitry Andric break; 5585ffd83dbSDimitry Andric case 'c': 5595ffd83dbSDimitry Andric Constant = true; 560bdd1243dSDimitry Andric [[fallthrough]]; 5615ffd83dbSDimitry Andric case 'p': 5625ffd83dbSDimitry Andric Pointer = true; 5635ffd83dbSDimitry Andric Bitwidth = ElementBitwidth; 5645ffd83dbSDimitry Andric NumVectors = 0; 5655ffd83dbSDimitry Andric break; 5665ffd83dbSDimitry Andric case 'e': 5675ffd83dbSDimitry Andric Signed = false; 5685ffd83dbSDimitry Andric ElementBitwidth /= 2; 5695ffd83dbSDimitry Andric break; 5705ffd83dbSDimitry Andric case 'h': 5715ffd83dbSDimitry Andric ElementBitwidth /= 2; 5725ffd83dbSDimitry Andric break; 5735ffd83dbSDimitry Andric case 'q': 5745ffd83dbSDimitry Andric ElementBitwidth /= 4; 5755ffd83dbSDimitry Andric break; 5765ffd83dbSDimitry Andric case 'b': 5775ffd83dbSDimitry Andric Signed = false; 5785ffd83dbSDimitry Andric Float = false; 5795ffd83dbSDimitry Andric BFloat = false; 5805ffd83dbSDimitry Andric ElementBitwidth /= 4; 5815ffd83dbSDimitry Andric break; 5825ffd83dbSDimitry Andric case 'o': 5835ffd83dbSDimitry Andric ElementBitwidth *= 4; 5845ffd83dbSDimitry Andric break; 5855ffd83dbSDimitry Andric case 'P': 5865ffd83dbSDimitry Andric Signed = true; 5875ffd83dbSDimitry Andric Float = false; 5885ffd83dbSDimitry Andric BFloat = false; 5895ffd83dbSDimitry Andric Predicate = true; 590*06c3fb27SDimitry Andric Svcount = false; 5915ffd83dbSDimitry Andric Bitwidth = 16; 5925ffd83dbSDimitry Andric ElementBitwidth = 1; 5935ffd83dbSDimitry Andric break; 5945ffd83dbSDimitry Andric case 's': 5955ffd83dbSDimitry Andric case 'a': 5965ffd83dbSDimitry Andric Bitwidth = ElementBitwidth; 5975ffd83dbSDimitry Andric NumVectors = 0; 5985ffd83dbSDimitry Andric break; 5995ffd83dbSDimitry Andric case 'R': 6005ffd83dbSDimitry Andric ElementBitwidth /= 2; 6015ffd83dbSDimitry Andric NumVectors = 0; 6025ffd83dbSDimitry Andric break; 6035ffd83dbSDimitry Andric case 'r': 6045ffd83dbSDimitry Andric ElementBitwidth /= 4; 6055ffd83dbSDimitry Andric NumVectors = 0; 6065ffd83dbSDimitry Andric break; 6075ffd83dbSDimitry Andric case '@': 6085ffd83dbSDimitry Andric Signed = false; 6095ffd83dbSDimitry Andric Float = false; 6105ffd83dbSDimitry Andric BFloat = false; 6115ffd83dbSDimitry Andric ElementBitwidth /= 4; 6125ffd83dbSDimitry Andric NumVectors = 0; 6135ffd83dbSDimitry Andric break; 6145ffd83dbSDimitry Andric case 'K': 6155ffd83dbSDimitry Andric Signed = true; 6165ffd83dbSDimitry Andric Float = false; 6175ffd83dbSDimitry Andric BFloat = false; 6185ffd83dbSDimitry Andric Bitwidth = ElementBitwidth; 6195ffd83dbSDimitry Andric NumVectors = 0; 6205ffd83dbSDimitry Andric break; 6215ffd83dbSDimitry Andric case 'L': 6225ffd83dbSDimitry Andric Signed = false; 6235ffd83dbSDimitry Andric Float = false; 6245ffd83dbSDimitry Andric BFloat = false; 6255ffd83dbSDimitry Andric Bitwidth = ElementBitwidth; 6265ffd83dbSDimitry Andric NumVectors = 0; 6275ffd83dbSDimitry Andric break; 6285ffd83dbSDimitry Andric case 'u': 6295ffd83dbSDimitry Andric Predicate = false; 630*06c3fb27SDimitry Andric Svcount = false; 6315ffd83dbSDimitry Andric Signed = false; 6325ffd83dbSDimitry Andric Float = false; 6335ffd83dbSDimitry Andric BFloat = false; 6345ffd83dbSDimitry Andric break; 6355ffd83dbSDimitry Andric case 'x': 6365ffd83dbSDimitry Andric Predicate = false; 637*06c3fb27SDimitry Andric Svcount = false; 6385ffd83dbSDimitry Andric Signed = true; 6395ffd83dbSDimitry Andric Float = false; 6405ffd83dbSDimitry Andric BFloat = false; 6415ffd83dbSDimitry Andric break; 6425ffd83dbSDimitry Andric case 'i': 6435ffd83dbSDimitry Andric Predicate = false; 644*06c3fb27SDimitry Andric Svcount = false; 6455ffd83dbSDimitry Andric Float = false; 6465ffd83dbSDimitry Andric BFloat = false; 6475ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 64; 6485ffd83dbSDimitry Andric NumVectors = 0; 6495ffd83dbSDimitry Andric Signed = false; 6505ffd83dbSDimitry Andric Immediate = true; 6515ffd83dbSDimitry Andric break; 6525ffd83dbSDimitry Andric case 'I': 6535ffd83dbSDimitry Andric Predicate = false; 654*06c3fb27SDimitry Andric Svcount = false; 6555ffd83dbSDimitry Andric Float = false; 6565ffd83dbSDimitry Andric BFloat = false; 6575ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 32; 6585ffd83dbSDimitry Andric NumVectors = 0; 6595ffd83dbSDimitry Andric Signed = true; 6605ffd83dbSDimitry Andric Immediate = true; 6615ffd83dbSDimitry Andric PredicatePattern = true; 6625ffd83dbSDimitry Andric break; 6635ffd83dbSDimitry Andric case 'J': 6645ffd83dbSDimitry Andric Predicate = false; 665*06c3fb27SDimitry Andric Svcount = false; 6665ffd83dbSDimitry Andric Float = false; 6675ffd83dbSDimitry Andric BFloat = false; 6685ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 32; 6695ffd83dbSDimitry Andric NumVectors = 0; 6705ffd83dbSDimitry Andric Signed = true; 6715ffd83dbSDimitry Andric Immediate = true; 6725ffd83dbSDimitry Andric PrefetchOp = true; 6735ffd83dbSDimitry Andric break; 6745ffd83dbSDimitry Andric case 'k': 6755ffd83dbSDimitry Andric Predicate = false; 676*06c3fb27SDimitry Andric Svcount = false; 6775ffd83dbSDimitry Andric Signed = true; 6785ffd83dbSDimitry Andric Float = false; 6795ffd83dbSDimitry Andric BFloat = false; 6805ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 32; 6815ffd83dbSDimitry Andric NumVectors = 0; 6825ffd83dbSDimitry Andric break; 6835ffd83dbSDimitry Andric case 'l': 6845ffd83dbSDimitry Andric Predicate = false; 685*06c3fb27SDimitry Andric Svcount = false; 6865ffd83dbSDimitry Andric Signed = true; 6875ffd83dbSDimitry Andric Float = false; 6885ffd83dbSDimitry Andric BFloat = false; 6895ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 64; 6905ffd83dbSDimitry Andric NumVectors = 0; 6915ffd83dbSDimitry Andric break; 6925ffd83dbSDimitry Andric case 'm': 6935ffd83dbSDimitry Andric Predicate = false; 694*06c3fb27SDimitry Andric Svcount = false; 6955ffd83dbSDimitry Andric Signed = false; 6965ffd83dbSDimitry Andric Float = false; 6975ffd83dbSDimitry Andric BFloat = false; 6985ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 32; 6995ffd83dbSDimitry Andric NumVectors = 0; 7005ffd83dbSDimitry Andric break; 7015ffd83dbSDimitry Andric case 'n': 7025ffd83dbSDimitry Andric Predicate = false; 703*06c3fb27SDimitry Andric Svcount = false; 7045ffd83dbSDimitry Andric Signed = false; 7055ffd83dbSDimitry Andric Float = false; 7065ffd83dbSDimitry Andric BFloat = false; 7075ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 64; 7085ffd83dbSDimitry Andric NumVectors = 0; 7095ffd83dbSDimitry Andric break; 7105ffd83dbSDimitry Andric case 'w': 7115ffd83dbSDimitry Andric ElementBitwidth = 64; 7125ffd83dbSDimitry Andric break; 7135ffd83dbSDimitry Andric case 'j': 7145ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 64; 7155ffd83dbSDimitry Andric NumVectors = 0; 7165ffd83dbSDimitry Andric break; 7175ffd83dbSDimitry Andric case 'f': 7185ffd83dbSDimitry Andric Signed = false; 7195ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 64; 7205ffd83dbSDimitry Andric NumVectors = 0; 7215ffd83dbSDimitry Andric break; 7225ffd83dbSDimitry Andric case 'g': 7235ffd83dbSDimitry Andric Signed = false; 7245ffd83dbSDimitry Andric Float = false; 7255ffd83dbSDimitry Andric BFloat = false; 7265ffd83dbSDimitry Andric ElementBitwidth = 64; 7275ffd83dbSDimitry Andric break; 7285ffd83dbSDimitry Andric case 't': 7295ffd83dbSDimitry Andric Signed = true; 7305ffd83dbSDimitry Andric Float = false; 7315ffd83dbSDimitry Andric BFloat = false; 7325ffd83dbSDimitry Andric ElementBitwidth = 32; 7335ffd83dbSDimitry Andric break; 7345ffd83dbSDimitry Andric case 'z': 7355ffd83dbSDimitry Andric Signed = false; 7365ffd83dbSDimitry Andric Float = false; 7375ffd83dbSDimitry Andric BFloat = false; 7385ffd83dbSDimitry Andric ElementBitwidth = 32; 7395ffd83dbSDimitry Andric break; 7405ffd83dbSDimitry Andric case 'O': 7415ffd83dbSDimitry Andric Predicate = false; 742*06c3fb27SDimitry Andric Svcount = false; 7435ffd83dbSDimitry Andric Float = true; 7445ffd83dbSDimitry Andric ElementBitwidth = 16; 7455ffd83dbSDimitry Andric break; 7465ffd83dbSDimitry Andric case 'M': 7475ffd83dbSDimitry Andric Predicate = false; 748*06c3fb27SDimitry Andric Svcount = false; 7495ffd83dbSDimitry Andric Float = true; 7505ffd83dbSDimitry Andric BFloat = false; 7515ffd83dbSDimitry Andric ElementBitwidth = 32; 7525ffd83dbSDimitry Andric break; 7535ffd83dbSDimitry Andric case 'N': 7545ffd83dbSDimitry Andric Predicate = false; 755*06c3fb27SDimitry Andric Svcount = false; 7565ffd83dbSDimitry Andric Float = true; 7575ffd83dbSDimitry Andric ElementBitwidth = 64; 7585ffd83dbSDimitry Andric break; 7595ffd83dbSDimitry Andric case 'Q': 7605ffd83dbSDimitry Andric Constant = true; 7615ffd83dbSDimitry Andric Pointer = true; 7625ffd83dbSDimitry Andric Void = true; 7635ffd83dbSDimitry Andric NumVectors = 0; 7645ffd83dbSDimitry Andric break; 7655ffd83dbSDimitry Andric case 'S': 7665ffd83dbSDimitry Andric Constant = true; 7675ffd83dbSDimitry Andric Pointer = true; 7685ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 8; 7695ffd83dbSDimitry Andric NumVectors = 0; 7705ffd83dbSDimitry Andric Signed = true; 7715ffd83dbSDimitry Andric break; 7725ffd83dbSDimitry Andric case 'W': 7735ffd83dbSDimitry Andric Constant = true; 7745ffd83dbSDimitry Andric Pointer = true; 7755ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 8; 7765ffd83dbSDimitry Andric NumVectors = 0; 7775ffd83dbSDimitry Andric Signed = false; 7785ffd83dbSDimitry Andric break; 7795ffd83dbSDimitry Andric case 'T': 7805ffd83dbSDimitry Andric Constant = true; 7815ffd83dbSDimitry Andric Pointer = true; 7825ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 16; 7835ffd83dbSDimitry Andric NumVectors = 0; 7845ffd83dbSDimitry Andric Signed = true; 7855ffd83dbSDimitry Andric break; 7865ffd83dbSDimitry Andric case 'X': 7875ffd83dbSDimitry Andric Constant = true; 7885ffd83dbSDimitry Andric Pointer = true; 7895ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 16; 7905ffd83dbSDimitry Andric NumVectors = 0; 7915ffd83dbSDimitry Andric Signed = false; 7925ffd83dbSDimitry Andric break; 7935ffd83dbSDimitry Andric case 'Y': 7945ffd83dbSDimitry Andric Constant = true; 7955ffd83dbSDimitry Andric Pointer = true; 7965ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 32; 7975ffd83dbSDimitry Andric NumVectors = 0; 7985ffd83dbSDimitry Andric Signed = false; 7995ffd83dbSDimitry Andric break; 8005ffd83dbSDimitry Andric case 'U': 8015ffd83dbSDimitry Andric Constant = true; 8025ffd83dbSDimitry Andric Pointer = true; 8035ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 32; 8045ffd83dbSDimitry Andric NumVectors = 0; 8055ffd83dbSDimitry Andric Signed = true; 8065ffd83dbSDimitry Andric break; 807*06c3fb27SDimitry Andric case '%': 808*06c3fb27SDimitry Andric Pointer = true; 809*06c3fb27SDimitry Andric Void = true; 810*06c3fb27SDimitry Andric NumVectors = 0; 811*06c3fb27SDimitry Andric break; 8125ffd83dbSDimitry Andric case 'A': 8135ffd83dbSDimitry Andric Pointer = true; 8145ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 8; 8155ffd83dbSDimitry Andric NumVectors = 0; 8165ffd83dbSDimitry Andric Signed = true; 8175ffd83dbSDimitry Andric break; 8185ffd83dbSDimitry Andric case 'B': 8195ffd83dbSDimitry Andric Pointer = true; 8205ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 16; 8215ffd83dbSDimitry Andric NumVectors = 0; 8225ffd83dbSDimitry Andric Signed = true; 8235ffd83dbSDimitry Andric break; 8245ffd83dbSDimitry Andric case 'C': 8255ffd83dbSDimitry Andric Pointer = true; 8265ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 32; 8275ffd83dbSDimitry Andric NumVectors = 0; 8285ffd83dbSDimitry Andric Signed = true; 8295ffd83dbSDimitry Andric break; 8305ffd83dbSDimitry Andric case 'D': 8315ffd83dbSDimitry Andric Pointer = true; 8325ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 64; 8335ffd83dbSDimitry Andric NumVectors = 0; 8345ffd83dbSDimitry Andric Signed = true; 8355ffd83dbSDimitry Andric break; 8365ffd83dbSDimitry Andric case 'E': 8375ffd83dbSDimitry Andric Pointer = true; 8385ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 8; 8395ffd83dbSDimitry Andric NumVectors = 0; 8405ffd83dbSDimitry Andric Signed = false; 8415ffd83dbSDimitry Andric break; 8425ffd83dbSDimitry Andric case 'F': 8435ffd83dbSDimitry Andric Pointer = true; 8445ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 16; 8455ffd83dbSDimitry Andric NumVectors = 0; 8465ffd83dbSDimitry Andric Signed = false; 8475ffd83dbSDimitry Andric break; 8485ffd83dbSDimitry Andric case 'G': 8495ffd83dbSDimitry Andric Pointer = true; 8505ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 32; 8515ffd83dbSDimitry Andric NumVectors = 0; 8525ffd83dbSDimitry Andric Signed = false; 8535ffd83dbSDimitry Andric break; 854*06c3fb27SDimitry Andric case '}': 855*06c3fb27SDimitry Andric Predicate = false; 856*06c3fb27SDimitry Andric Signed = true; 857*06c3fb27SDimitry Andric Svcount = true; 858*06c3fb27SDimitry Andric NumVectors = 0; 859*06c3fb27SDimitry Andric Float = false; 860*06c3fb27SDimitry Andric BFloat = false; 861*06c3fb27SDimitry Andric break; 8625ffd83dbSDimitry Andric default: 8635ffd83dbSDimitry Andric llvm_unreachable("Unhandled character!"); 8645ffd83dbSDimitry Andric } 8655ffd83dbSDimitry Andric } 8665ffd83dbSDimitry Andric 8675ffd83dbSDimitry Andric 8685ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 8695ffd83dbSDimitry Andric // Intrinsic implementation 8705ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 8715ffd83dbSDimitry Andric 8725ffd83dbSDimitry Andric Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy, 8735ffd83dbSDimitry Andric StringRef MergeSuffix, uint64_t MemoryElementTy, 8745ffd83dbSDimitry Andric StringRef LLVMName, uint64_t Flags, 8755ffd83dbSDimitry Andric ArrayRef<ImmCheck> Checks, TypeSpec BT, ClassKind Class, 8765ffd83dbSDimitry Andric SVEEmitter &Emitter, StringRef Guard) 8775ffd83dbSDimitry Andric : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()), 8785ffd83dbSDimitry Andric BaseTypeSpec(BT), Class(Class), Guard(Guard.str()), 8795ffd83dbSDimitry Andric MergeSuffix(MergeSuffix.str()), BaseType(BT, 'd'), Flags(Flags), 8805ffd83dbSDimitry Andric ImmChecks(Checks.begin(), Checks.end()) { 8815ffd83dbSDimitry Andric // Types[0] is the return value. 8825ffd83dbSDimitry Andric for (unsigned I = 0; I < Proto.size(); ++I) { 8835ffd83dbSDimitry Andric SVEType T(BaseTypeSpec, Proto[I]); 8845ffd83dbSDimitry Andric Types.push_back(T); 8855ffd83dbSDimitry Andric 8865ffd83dbSDimitry Andric // Add range checks for immediates 8875ffd83dbSDimitry Andric if (I > 0) { 8885ffd83dbSDimitry Andric if (T.isPredicatePattern()) 8895ffd83dbSDimitry Andric ImmChecks.emplace_back( 8905ffd83dbSDimitry Andric I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_31")); 8915ffd83dbSDimitry Andric else if (T.isPrefetchOp()) 8925ffd83dbSDimitry Andric ImmChecks.emplace_back( 8935ffd83dbSDimitry Andric I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_13")); 8945ffd83dbSDimitry Andric } 8955ffd83dbSDimitry Andric } 8965ffd83dbSDimitry Andric 8975ffd83dbSDimitry Andric // Set flags based on properties 8985ffd83dbSDimitry Andric this->Flags |= Emitter.encodeTypeFlags(BaseType); 8995ffd83dbSDimitry Andric this->Flags |= Emitter.encodeMemoryElementType(MemoryElementTy); 9005ffd83dbSDimitry Andric this->Flags |= Emitter.encodeMergeType(MergeTy); 9015ffd83dbSDimitry Andric if (hasSplat()) 9025ffd83dbSDimitry Andric this->Flags |= Emitter.encodeSplatOperand(getSplatIdx()); 9035ffd83dbSDimitry Andric } 9045ffd83dbSDimitry Andric 9055ffd83dbSDimitry Andric std::string Intrinsic::getBuiltinTypeStr() { 9065ffd83dbSDimitry Andric std::string S = getReturnType().builtin_str(); 9075ffd83dbSDimitry Andric for (unsigned I = 0; I < getNumParams(); ++I) 9085ffd83dbSDimitry Andric S += getParamType(I).builtin_str(); 9095ffd83dbSDimitry Andric 9105ffd83dbSDimitry Andric return S; 9115ffd83dbSDimitry Andric } 9125ffd83dbSDimitry Andric 9135ffd83dbSDimitry Andric std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS, 9145ffd83dbSDimitry Andric std::string Proto) const { 9155ffd83dbSDimitry Andric std::string Ret = Name; 9165ffd83dbSDimitry Andric while (Ret.find('{') != std::string::npos) { 9175ffd83dbSDimitry Andric size_t Pos = Ret.find('{'); 9185ffd83dbSDimitry Andric size_t End = Ret.find('}'); 9195ffd83dbSDimitry Andric unsigned NumChars = End - Pos + 1; 9205ffd83dbSDimitry Andric assert(NumChars == 3 && "Unexpected template argument"); 9215ffd83dbSDimitry Andric 9225ffd83dbSDimitry Andric SVEType T; 9235ffd83dbSDimitry Andric char C = Ret[Pos+1]; 9245ffd83dbSDimitry Andric switch(C) { 9255ffd83dbSDimitry Andric default: 9265ffd83dbSDimitry Andric llvm_unreachable("Unknown predication specifier"); 9275ffd83dbSDimitry Andric case 'd': 9285ffd83dbSDimitry Andric T = SVEType(TS, 'd'); 9295ffd83dbSDimitry Andric break; 9305ffd83dbSDimitry Andric case '0': 9315ffd83dbSDimitry Andric case '1': 9325ffd83dbSDimitry Andric case '2': 9335ffd83dbSDimitry Andric case '3': 9345ffd83dbSDimitry Andric T = SVEType(TS, Proto[C - '0']); 9355ffd83dbSDimitry Andric break; 9365ffd83dbSDimitry Andric } 9375ffd83dbSDimitry Andric 9385ffd83dbSDimitry Andric // Replace templated arg with the right suffix (e.g. u32) 9395ffd83dbSDimitry Andric std::string TypeCode; 9405ffd83dbSDimitry Andric if (T.isInteger()) 9415ffd83dbSDimitry Andric TypeCode = T.isSigned() ? 's' : 'u'; 942*06c3fb27SDimitry Andric else if (T.isSvcount()) 943*06c3fb27SDimitry Andric TypeCode = 'c'; 9445ffd83dbSDimitry Andric else if (T.isPredicateVector()) 9455ffd83dbSDimitry Andric TypeCode = 'b'; 9465ffd83dbSDimitry Andric else if (T.isBFloat()) 9475ffd83dbSDimitry Andric TypeCode = "bf"; 9485ffd83dbSDimitry Andric else 9495ffd83dbSDimitry Andric TypeCode = 'f'; 9505ffd83dbSDimitry Andric Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits())); 9515ffd83dbSDimitry Andric } 9525ffd83dbSDimitry Andric 9535ffd83dbSDimitry Andric return Ret; 9545ffd83dbSDimitry Andric } 9555ffd83dbSDimitry Andric 956*06c3fb27SDimitry Andric std::string Intrinsic::mangleLLVMName() const { 957*06c3fb27SDimitry Andric std::string S = getLLVMName(); 958*06c3fb27SDimitry Andric 959*06c3fb27SDimitry Andric // Replace all {d} like expressions with e.g. 'u32' 960*06c3fb27SDimitry Andric return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()); 961*06c3fb27SDimitry Andric } 962*06c3fb27SDimitry Andric 9635ffd83dbSDimitry Andric std::string Intrinsic::mangleName(ClassKind LocalCK) const { 9645ffd83dbSDimitry Andric std::string S = getName(); 9655ffd83dbSDimitry Andric 9665ffd83dbSDimitry Andric if (LocalCK == ClassG) { 9675ffd83dbSDimitry Andric // Remove the square brackets and everything in between. 968e8d8bef9SDimitry Andric while (S.find('[') != std::string::npos) { 969e8d8bef9SDimitry Andric auto Start = S.find('['); 9705ffd83dbSDimitry Andric auto End = S.find(']'); 9715ffd83dbSDimitry Andric S.erase(Start, (End-Start)+1); 9725ffd83dbSDimitry Andric } 9735ffd83dbSDimitry Andric } else { 9745ffd83dbSDimitry Andric // Remove the square brackets. 975e8d8bef9SDimitry Andric while (S.find('[') != std::string::npos) { 9765ffd83dbSDimitry Andric auto BrPos = S.find('['); 9775ffd83dbSDimitry Andric if (BrPos != std::string::npos) 9785ffd83dbSDimitry Andric S.erase(BrPos, 1); 9795ffd83dbSDimitry Andric BrPos = S.find(']'); 9805ffd83dbSDimitry Andric if (BrPos != std::string::npos) 9815ffd83dbSDimitry Andric S.erase(BrPos, 1); 9825ffd83dbSDimitry Andric } 9835ffd83dbSDimitry Andric } 9845ffd83dbSDimitry Andric 9855ffd83dbSDimitry Andric // Replace all {d} like expressions with e.g. 'u32' 9865ffd83dbSDimitry Andric return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) + 9875ffd83dbSDimitry Andric getMergeSuffix(); 9885ffd83dbSDimitry Andric } 9895ffd83dbSDimitry Andric 990*06c3fb27SDimitry Andric void Intrinsic::emitIntrinsic(raw_ostream &OS, SVEEmitter &Emitter) const { 991fe6060f1SDimitry Andric bool IsOverloaded = getClassKind() == ClassG && getProto().size() > 1; 9925ffd83dbSDimitry Andric 993fe6060f1SDimitry Andric std::string FullName = mangleName(ClassS); 994fe6060f1SDimitry Andric std::string ProtoName = mangleName(getClassKind()); 995*06c3fb27SDimitry Andric std::string SMEAttrs = ""; 996*06c3fb27SDimitry Andric 997*06c3fb27SDimitry Andric if (Flags & Emitter.getEnumValueForFlag("IsStreaming")) 998*06c3fb27SDimitry Andric SMEAttrs += ", arm_streaming"; 999*06c3fb27SDimitry Andric if (Flags & Emitter.getEnumValueForFlag("IsStreamingCompatible")) 1000*06c3fb27SDimitry Andric SMEAttrs += ", arm_streaming_compatible"; 1001*06c3fb27SDimitry Andric if (Flags & Emitter.getEnumValueForFlag("IsSharedZA")) 1002*06c3fb27SDimitry Andric SMEAttrs += ", arm_shared_za"; 1003*06c3fb27SDimitry Andric if (Flags & Emitter.getEnumValueForFlag("IsPreservesZA")) 1004*06c3fb27SDimitry Andric SMEAttrs += ", arm_preserves_za"; 1005fe6060f1SDimitry Andric 1006fe6060f1SDimitry Andric OS << (IsOverloaded ? "__aio " : "__ai ") 1007fe6060f1SDimitry Andric << "__attribute__((__clang_arm_builtin_alias(" 1008*06c3fb27SDimitry Andric << (SMEAttrs.empty() ? "__builtin_sve_" : "__builtin_sme_") 1009*06c3fb27SDimitry Andric << FullName << ")"; 1010*06c3fb27SDimitry Andric if (!SMEAttrs.empty()) 1011*06c3fb27SDimitry Andric OS << SMEAttrs; 1012*06c3fb27SDimitry Andric OS << "))\n"; 10135ffd83dbSDimitry Andric 10145ffd83dbSDimitry Andric OS << getTypes()[0].str() << " " << ProtoName << "("; 10155ffd83dbSDimitry Andric for (unsigned I = 0; I < getTypes().size() - 1; ++I) { 10165ffd83dbSDimitry Andric if (I != 0) 10175ffd83dbSDimitry Andric OS << ", "; 10185ffd83dbSDimitry Andric OS << getTypes()[I + 1].str(); 10195ffd83dbSDimitry Andric } 10205ffd83dbSDimitry Andric OS << ");\n"; 10215ffd83dbSDimitry Andric } 10225ffd83dbSDimitry Andric 10235ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 10245ffd83dbSDimitry Andric // SVEEmitter implementation 10255ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 10265ffd83dbSDimitry Andric uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) { 10275ffd83dbSDimitry Andric if (T.isFloat()) { 10285ffd83dbSDimitry Andric switch (T.getElementSizeInBits()) { 10295ffd83dbSDimitry Andric case 16: 10305ffd83dbSDimitry Andric return encodeEltType("EltTyFloat16"); 10315ffd83dbSDimitry Andric case 32: 10325ffd83dbSDimitry Andric return encodeEltType("EltTyFloat32"); 10335ffd83dbSDimitry Andric case 64: 10345ffd83dbSDimitry Andric return encodeEltType("EltTyFloat64"); 10355ffd83dbSDimitry Andric default: 10365ffd83dbSDimitry Andric llvm_unreachable("Unhandled float element bitwidth!"); 10375ffd83dbSDimitry Andric } 10385ffd83dbSDimitry Andric } 10395ffd83dbSDimitry Andric 10405ffd83dbSDimitry Andric if (T.isBFloat()) { 10415ffd83dbSDimitry Andric assert(T.getElementSizeInBits() == 16 && "Not a valid BFloat."); 10425ffd83dbSDimitry Andric return encodeEltType("EltTyBFloat16"); 10435ffd83dbSDimitry Andric } 10445ffd83dbSDimitry Andric 1045*06c3fb27SDimitry Andric if (T.isPredicateVector() || T.isSvcount()) { 10465ffd83dbSDimitry Andric switch (T.getElementSizeInBits()) { 10475ffd83dbSDimitry Andric case 8: 10485ffd83dbSDimitry Andric return encodeEltType("EltTyBool8"); 10495ffd83dbSDimitry Andric case 16: 10505ffd83dbSDimitry Andric return encodeEltType("EltTyBool16"); 10515ffd83dbSDimitry Andric case 32: 10525ffd83dbSDimitry Andric return encodeEltType("EltTyBool32"); 10535ffd83dbSDimitry Andric case 64: 10545ffd83dbSDimitry Andric return encodeEltType("EltTyBool64"); 10555ffd83dbSDimitry Andric default: 10565ffd83dbSDimitry Andric llvm_unreachable("Unhandled predicate element bitwidth!"); 10575ffd83dbSDimitry Andric } 10585ffd83dbSDimitry Andric } 10595ffd83dbSDimitry Andric 10605ffd83dbSDimitry Andric switch (T.getElementSizeInBits()) { 10615ffd83dbSDimitry Andric case 8: 10625ffd83dbSDimitry Andric return encodeEltType("EltTyInt8"); 10635ffd83dbSDimitry Andric case 16: 10645ffd83dbSDimitry Andric return encodeEltType("EltTyInt16"); 10655ffd83dbSDimitry Andric case 32: 10665ffd83dbSDimitry Andric return encodeEltType("EltTyInt32"); 10675ffd83dbSDimitry Andric case 64: 10685ffd83dbSDimitry Andric return encodeEltType("EltTyInt64"); 1069*06c3fb27SDimitry Andric case 128: 1070*06c3fb27SDimitry Andric return encodeEltType("EltTyInt128"); 10715ffd83dbSDimitry Andric default: 10725ffd83dbSDimitry Andric llvm_unreachable("Unhandled integer element bitwidth!"); 10735ffd83dbSDimitry Andric } 10745ffd83dbSDimitry Andric } 10755ffd83dbSDimitry Andric 10765ffd83dbSDimitry Andric void SVEEmitter::createIntrinsic( 10775ffd83dbSDimitry Andric Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) { 10785ffd83dbSDimitry Andric StringRef Name = R->getValueAsString("Name"); 10795ffd83dbSDimitry Andric StringRef Proto = R->getValueAsString("Prototype"); 10805ffd83dbSDimitry Andric StringRef Types = R->getValueAsString("Types"); 1081bdd1243dSDimitry Andric StringRef Guard = R->getValueAsString("TargetGuard"); 10825ffd83dbSDimitry Andric StringRef LLVMName = R->getValueAsString("LLVMIntrinsic"); 10835ffd83dbSDimitry Andric uint64_t Merge = R->getValueAsInt("Merge"); 10845ffd83dbSDimitry Andric StringRef MergeSuffix = R->getValueAsString("MergeSuffix"); 10855ffd83dbSDimitry Andric uint64_t MemEltType = R->getValueAsInt("MemEltType"); 10865ffd83dbSDimitry Andric std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags"); 10875ffd83dbSDimitry Andric std::vector<Record*> ImmCheckList = R->getValueAsListOfDefs("ImmChecks"); 10885ffd83dbSDimitry Andric 10895ffd83dbSDimitry Andric int64_t Flags = 0; 10905ffd83dbSDimitry Andric for (auto FlagRec : FlagsList) 10915ffd83dbSDimitry Andric Flags |= FlagRec->getValueAsInt("Value"); 10925ffd83dbSDimitry Andric 10935ffd83dbSDimitry Andric // Create a dummy TypeSpec for non-overloaded builtins. 10945ffd83dbSDimitry Andric if (Types.empty()) { 10955ffd83dbSDimitry Andric assert((Flags & getEnumValueForFlag("IsOverloadNone")) && 10965ffd83dbSDimitry Andric "Expect TypeSpec for overloaded builtin!"); 10975ffd83dbSDimitry Andric Types = "i"; 10985ffd83dbSDimitry Andric } 10995ffd83dbSDimitry Andric 11005ffd83dbSDimitry Andric // Extract type specs from string 11015ffd83dbSDimitry Andric SmallVector<TypeSpec, 8> TypeSpecs; 11025ffd83dbSDimitry Andric TypeSpec Acc; 11035ffd83dbSDimitry Andric for (char I : Types) { 11045ffd83dbSDimitry Andric Acc.push_back(I); 11055ffd83dbSDimitry Andric if (islower(I)) { 11065ffd83dbSDimitry Andric TypeSpecs.push_back(TypeSpec(Acc)); 11075ffd83dbSDimitry Andric Acc.clear(); 11085ffd83dbSDimitry Andric } 11095ffd83dbSDimitry Andric } 11105ffd83dbSDimitry Andric 11115ffd83dbSDimitry Andric // Remove duplicate type specs. 11125ffd83dbSDimitry Andric llvm::sort(TypeSpecs); 11135ffd83dbSDimitry Andric TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()), 11145ffd83dbSDimitry Andric TypeSpecs.end()); 11155ffd83dbSDimitry Andric 11165ffd83dbSDimitry Andric // Create an Intrinsic for each type spec. 11175ffd83dbSDimitry Andric for (auto TS : TypeSpecs) { 11185ffd83dbSDimitry Andric // Collate a list of range/option checks for the immediates. 11195ffd83dbSDimitry Andric SmallVector<ImmCheck, 2> ImmChecks; 11205ffd83dbSDimitry Andric for (auto *R : ImmCheckList) { 11215ffd83dbSDimitry Andric int64_t Arg = R->getValueAsInt("Arg"); 11225ffd83dbSDimitry Andric int64_t EltSizeArg = R->getValueAsInt("EltSizeArg"); 11235ffd83dbSDimitry Andric int64_t Kind = R->getValueAsDef("Kind")->getValueAsInt("Value"); 11245ffd83dbSDimitry Andric assert(Arg >= 0 && Kind >= 0 && "Arg and Kind must be nonnegative"); 11255ffd83dbSDimitry Andric 11265ffd83dbSDimitry Andric unsigned ElementSizeInBits = 0; 11275ffd83dbSDimitry Andric if (EltSizeArg >= 0) 11285ffd83dbSDimitry Andric ElementSizeInBits = 11295ffd83dbSDimitry Andric SVEType(TS, Proto[EltSizeArg + /* offset by return arg */ 1]) 11305ffd83dbSDimitry Andric .getElementSizeInBits(); 11315ffd83dbSDimitry Andric ImmChecks.push_back(ImmCheck(Arg, Kind, ElementSizeInBits)); 11325ffd83dbSDimitry Andric } 11335ffd83dbSDimitry Andric 11345ffd83dbSDimitry Andric Out.push_back(std::make_unique<Intrinsic>( 11355ffd83dbSDimitry Andric Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, ImmChecks, 11365ffd83dbSDimitry Andric TS, ClassS, *this, Guard)); 11375ffd83dbSDimitry Andric 11385ffd83dbSDimitry Andric // Also generate the short-form (e.g. svadd_m) for the given type-spec. 11395ffd83dbSDimitry Andric if (Intrinsic::isOverloadedIntrinsic(Name)) 11405ffd83dbSDimitry Andric Out.push_back(std::make_unique<Intrinsic>( 11415ffd83dbSDimitry Andric Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, 11425ffd83dbSDimitry Andric ImmChecks, TS, ClassG, *this, Guard)); 11435ffd83dbSDimitry Andric } 11445ffd83dbSDimitry Andric } 11455ffd83dbSDimitry Andric 11465ffd83dbSDimitry Andric void SVEEmitter::createHeader(raw_ostream &OS) { 11475ffd83dbSDimitry Andric OS << "/*===---- arm_sve.h - ARM SVE intrinsics " 11485ffd83dbSDimitry Andric "-----------------------------------===\n" 11495ffd83dbSDimitry Andric " *\n" 11505ffd83dbSDimitry Andric " *\n" 11515ffd83dbSDimitry Andric " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " 11525ffd83dbSDimitry Andric "Exceptions.\n" 11535ffd83dbSDimitry Andric " * See https://llvm.org/LICENSE.txt for license information.\n" 11545ffd83dbSDimitry Andric " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 11555ffd83dbSDimitry Andric " *\n" 11565ffd83dbSDimitry Andric " *===-----------------------------------------------------------------" 11575ffd83dbSDimitry Andric "------===\n" 11585ffd83dbSDimitry Andric " */\n\n"; 11595ffd83dbSDimitry Andric 11605ffd83dbSDimitry Andric OS << "#ifndef __ARM_SVE_H\n"; 11615ffd83dbSDimitry Andric OS << "#define __ARM_SVE_H\n\n"; 11625ffd83dbSDimitry Andric 11635ffd83dbSDimitry Andric OS << "#if !defined(__LITTLE_ENDIAN__)\n"; 11645ffd83dbSDimitry Andric OS << "#error \"Big endian is currently not supported for arm_sve.h\"\n"; 11655ffd83dbSDimitry Andric OS << "#endif\n"; 11665ffd83dbSDimitry Andric 11675ffd83dbSDimitry Andric OS << "#include <stdint.h>\n\n"; 11685ffd83dbSDimitry Andric OS << "#ifdef __cplusplus\n"; 11695ffd83dbSDimitry Andric OS << "extern \"C\" {\n"; 11705ffd83dbSDimitry Andric OS << "#else\n"; 11715ffd83dbSDimitry Andric OS << "#include <stdbool.h>\n"; 11725ffd83dbSDimitry Andric OS << "#endif\n\n"; 11735ffd83dbSDimitry Andric 11745ffd83dbSDimitry Andric OS << "typedef __fp16 float16_t;\n"; 11755ffd83dbSDimitry Andric OS << "typedef float float32_t;\n"; 11765ffd83dbSDimitry Andric OS << "typedef double float64_t;\n"; 11775ffd83dbSDimitry Andric 11785ffd83dbSDimitry Andric OS << "typedef __SVInt8_t svint8_t;\n"; 11795ffd83dbSDimitry Andric OS << "typedef __SVInt16_t svint16_t;\n"; 11805ffd83dbSDimitry Andric OS << "typedef __SVInt32_t svint32_t;\n"; 11815ffd83dbSDimitry Andric OS << "typedef __SVInt64_t svint64_t;\n"; 11825ffd83dbSDimitry Andric OS << "typedef __SVUint8_t svuint8_t;\n"; 11835ffd83dbSDimitry Andric OS << "typedef __SVUint16_t svuint16_t;\n"; 11845ffd83dbSDimitry Andric OS << "typedef __SVUint32_t svuint32_t;\n"; 11855ffd83dbSDimitry Andric OS << "typedef __SVUint64_t svuint64_t;\n"; 11865ffd83dbSDimitry Andric OS << "typedef __SVFloat16_t svfloat16_t;\n\n"; 11875ffd83dbSDimitry Andric 11885ffd83dbSDimitry Andric OS << "typedef __SVBFloat16_t svbfloat16_t;\n"; 11895ffd83dbSDimitry Andric 11905ffd83dbSDimitry Andric OS << "#include <arm_bf16.h>\n"; 11915ffd83dbSDimitry Andric 11925ffd83dbSDimitry Andric OS << "typedef __SVFloat32_t svfloat32_t;\n"; 11935ffd83dbSDimitry Andric OS << "typedef __SVFloat64_t svfloat64_t;\n"; 11945ffd83dbSDimitry Andric OS << "typedef __clang_svint8x2_t svint8x2_t;\n"; 11955ffd83dbSDimitry Andric OS << "typedef __clang_svint16x2_t svint16x2_t;\n"; 11965ffd83dbSDimitry Andric OS << "typedef __clang_svint32x2_t svint32x2_t;\n"; 11975ffd83dbSDimitry Andric OS << "typedef __clang_svint64x2_t svint64x2_t;\n"; 11985ffd83dbSDimitry Andric OS << "typedef __clang_svuint8x2_t svuint8x2_t;\n"; 11995ffd83dbSDimitry Andric OS << "typedef __clang_svuint16x2_t svuint16x2_t;\n"; 12005ffd83dbSDimitry Andric OS << "typedef __clang_svuint32x2_t svuint32x2_t;\n"; 12015ffd83dbSDimitry Andric OS << "typedef __clang_svuint64x2_t svuint64x2_t;\n"; 12025ffd83dbSDimitry Andric OS << "typedef __clang_svfloat16x2_t svfloat16x2_t;\n"; 12035ffd83dbSDimitry Andric OS << "typedef __clang_svfloat32x2_t svfloat32x2_t;\n"; 12045ffd83dbSDimitry Andric OS << "typedef __clang_svfloat64x2_t svfloat64x2_t;\n"; 12055ffd83dbSDimitry Andric OS << "typedef __clang_svint8x3_t svint8x3_t;\n"; 12065ffd83dbSDimitry Andric OS << "typedef __clang_svint16x3_t svint16x3_t;\n"; 12075ffd83dbSDimitry Andric OS << "typedef __clang_svint32x3_t svint32x3_t;\n"; 12085ffd83dbSDimitry Andric OS << "typedef __clang_svint64x3_t svint64x3_t;\n"; 12095ffd83dbSDimitry Andric OS << "typedef __clang_svuint8x3_t svuint8x3_t;\n"; 12105ffd83dbSDimitry Andric OS << "typedef __clang_svuint16x3_t svuint16x3_t;\n"; 12115ffd83dbSDimitry Andric OS << "typedef __clang_svuint32x3_t svuint32x3_t;\n"; 12125ffd83dbSDimitry Andric OS << "typedef __clang_svuint64x3_t svuint64x3_t;\n"; 12135ffd83dbSDimitry Andric OS << "typedef __clang_svfloat16x3_t svfloat16x3_t;\n"; 12145ffd83dbSDimitry Andric OS << "typedef __clang_svfloat32x3_t svfloat32x3_t;\n"; 12155ffd83dbSDimitry Andric OS << "typedef __clang_svfloat64x3_t svfloat64x3_t;\n"; 12165ffd83dbSDimitry Andric OS << "typedef __clang_svint8x4_t svint8x4_t;\n"; 12175ffd83dbSDimitry Andric OS << "typedef __clang_svint16x4_t svint16x4_t;\n"; 12185ffd83dbSDimitry Andric OS << "typedef __clang_svint32x4_t svint32x4_t;\n"; 12195ffd83dbSDimitry Andric OS << "typedef __clang_svint64x4_t svint64x4_t;\n"; 12205ffd83dbSDimitry Andric OS << "typedef __clang_svuint8x4_t svuint8x4_t;\n"; 12215ffd83dbSDimitry Andric OS << "typedef __clang_svuint16x4_t svuint16x4_t;\n"; 12225ffd83dbSDimitry Andric OS << "typedef __clang_svuint32x4_t svuint32x4_t;\n"; 12235ffd83dbSDimitry Andric OS << "typedef __clang_svuint64x4_t svuint64x4_t;\n"; 12245ffd83dbSDimitry Andric OS << "typedef __clang_svfloat16x4_t svfloat16x4_t;\n"; 12255ffd83dbSDimitry Andric OS << "typedef __clang_svfloat32x4_t svfloat32x4_t;\n"; 12265ffd83dbSDimitry Andric OS << "typedef __clang_svfloat64x4_t svfloat64x4_t;\n"; 1227*06c3fb27SDimitry Andric OS << "typedef __SVBool_t svbool_t;\n"; 1228*06c3fb27SDimitry Andric OS << "typedef __clang_svboolx2_t svboolx2_t;\n"; 1229*06c3fb27SDimitry Andric OS << "typedef __clang_svboolx4_t svboolx4_t;\n\n"; 12305ffd83dbSDimitry Andric 12315ffd83dbSDimitry Andric OS << "typedef __clang_svbfloat16x2_t svbfloat16x2_t;\n"; 12325ffd83dbSDimitry Andric OS << "typedef __clang_svbfloat16x3_t svbfloat16x3_t;\n"; 12335ffd83dbSDimitry Andric OS << "typedef __clang_svbfloat16x4_t svbfloat16x4_t;\n"; 12345ffd83dbSDimitry Andric 1235*06c3fb27SDimitry Andric OS << "typedef __SVCount_t svcount_t;\n\n"; 1236*06c3fb27SDimitry Andric 1237e8d8bef9SDimitry Andric OS << "enum svpattern\n"; 12385ffd83dbSDimitry Andric OS << "{\n"; 12395ffd83dbSDimitry Andric OS << " SV_POW2 = 0,\n"; 12405ffd83dbSDimitry Andric OS << " SV_VL1 = 1,\n"; 12415ffd83dbSDimitry Andric OS << " SV_VL2 = 2,\n"; 12425ffd83dbSDimitry Andric OS << " SV_VL3 = 3,\n"; 12435ffd83dbSDimitry Andric OS << " SV_VL4 = 4,\n"; 12445ffd83dbSDimitry Andric OS << " SV_VL5 = 5,\n"; 12455ffd83dbSDimitry Andric OS << " SV_VL6 = 6,\n"; 12465ffd83dbSDimitry Andric OS << " SV_VL7 = 7,\n"; 12475ffd83dbSDimitry Andric OS << " SV_VL8 = 8,\n"; 12485ffd83dbSDimitry Andric OS << " SV_VL16 = 9,\n"; 12495ffd83dbSDimitry Andric OS << " SV_VL32 = 10,\n"; 12505ffd83dbSDimitry Andric OS << " SV_VL64 = 11,\n"; 12515ffd83dbSDimitry Andric OS << " SV_VL128 = 12,\n"; 12525ffd83dbSDimitry Andric OS << " SV_VL256 = 13,\n"; 12535ffd83dbSDimitry Andric OS << " SV_MUL4 = 29,\n"; 12545ffd83dbSDimitry Andric OS << " SV_MUL3 = 30,\n"; 12555ffd83dbSDimitry Andric OS << " SV_ALL = 31\n"; 1256e8d8bef9SDimitry Andric OS << "};\n\n"; 12575ffd83dbSDimitry Andric 1258e8d8bef9SDimitry Andric OS << "enum svprfop\n"; 12595ffd83dbSDimitry Andric OS << "{\n"; 12605ffd83dbSDimitry Andric OS << " SV_PLDL1KEEP = 0,\n"; 12615ffd83dbSDimitry Andric OS << " SV_PLDL1STRM = 1,\n"; 12625ffd83dbSDimitry Andric OS << " SV_PLDL2KEEP = 2,\n"; 12635ffd83dbSDimitry Andric OS << " SV_PLDL2STRM = 3,\n"; 12645ffd83dbSDimitry Andric OS << " SV_PLDL3KEEP = 4,\n"; 12655ffd83dbSDimitry Andric OS << " SV_PLDL3STRM = 5,\n"; 12665ffd83dbSDimitry Andric OS << " SV_PSTL1KEEP = 8,\n"; 12675ffd83dbSDimitry Andric OS << " SV_PSTL1STRM = 9,\n"; 12685ffd83dbSDimitry Andric OS << " SV_PSTL2KEEP = 10,\n"; 12695ffd83dbSDimitry Andric OS << " SV_PSTL2STRM = 11,\n"; 12705ffd83dbSDimitry Andric OS << " SV_PSTL3KEEP = 12,\n"; 12715ffd83dbSDimitry Andric OS << " SV_PSTL3STRM = 13\n"; 1272e8d8bef9SDimitry Andric OS << "};\n\n"; 12735ffd83dbSDimitry Andric 12745ffd83dbSDimitry Andric OS << "/* Function attributes */\n"; 1275fe6060f1SDimitry Andric OS << "#define __ai static __inline__ __attribute__((__always_inline__, " 1276fe6060f1SDimitry Andric "__nodebug__))\n\n"; 1277fe6060f1SDimitry Andric OS << "#define __aio static __inline__ __attribute__((__always_inline__, " 12785ffd83dbSDimitry Andric "__nodebug__, __overloadable__))\n\n"; 12795ffd83dbSDimitry Andric 12805ffd83dbSDimitry Andric // Add reinterpret functions. 12815ffd83dbSDimitry Andric for (auto ShortForm : { false, true } ) 12825ffd83dbSDimitry Andric for (const ReinterpretTypeInfo &From : Reinterprets) 12835ffd83dbSDimitry Andric for (const ReinterpretTypeInfo &To : Reinterprets) { 12845ffd83dbSDimitry Andric if (ShortForm) { 1285bdd1243dSDimitry Andric OS << "__aio __attribute__((target(\"sve\"))) " << From.Type 1286bdd1243dSDimitry Andric << " svreinterpret_" << From.Suffix; 12875ffd83dbSDimitry Andric OS << "(" << To.Type << " op) {\n"; 12885ffd83dbSDimitry Andric OS << " return __builtin_sve_reinterpret_" << From.Suffix << "_" 12895ffd83dbSDimitry Andric << To.Suffix << "(op);\n"; 12905ffd83dbSDimitry Andric OS << "}\n\n"; 12915ffd83dbSDimitry Andric } else 12925ffd83dbSDimitry Andric OS << "#define svreinterpret_" << From.Suffix << "_" << To.Suffix 12935ffd83dbSDimitry Andric << "(...) __builtin_sve_reinterpret_" << From.Suffix << "_" 12945ffd83dbSDimitry Andric << To.Suffix << "(__VA_ARGS__)\n"; 12955ffd83dbSDimitry Andric } 12965ffd83dbSDimitry Andric 12975ffd83dbSDimitry Andric SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 12985ffd83dbSDimitry Andric std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 12995ffd83dbSDimitry Andric for (auto *R : RV) 13005ffd83dbSDimitry Andric createIntrinsic(R, Defs); 13015ffd83dbSDimitry Andric 13025ffd83dbSDimitry Andric // Sort intrinsics in header file by following order/priority: 13035ffd83dbSDimitry Andric // - Architectural guard (i.e. does it require SVE2 or SVE2_AES) 13045ffd83dbSDimitry Andric // - Class (is intrinsic overloaded or not) 13055ffd83dbSDimitry Andric // - Intrinsic name 13065ffd83dbSDimitry Andric std::stable_sort( 13075ffd83dbSDimitry Andric Defs.begin(), Defs.end(), [](const std::unique_ptr<Intrinsic> &A, 13085ffd83dbSDimitry Andric const std::unique_ptr<Intrinsic> &B) { 13095ffd83dbSDimitry Andric auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) { 13105ffd83dbSDimitry Andric return std::make_tuple(I->getGuard(), (unsigned)I->getClassKind(), I->getName()); 13115ffd83dbSDimitry Andric }; 13125ffd83dbSDimitry Andric return ToTuple(A) < ToTuple(B); 13135ffd83dbSDimitry Andric }); 13145ffd83dbSDimitry Andric 1315bdd1243dSDimitry Andric // Actually emit the intrinsic declarations. 1316bdd1243dSDimitry Andric for (auto &I : Defs) 1317*06c3fb27SDimitry Andric I->emitIntrinsic(OS, *this); 13185ffd83dbSDimitry Andric 13195ffd83dbSDimitry Andric OS << "#define svcvtnt_bf16_x svcvtnt_bf16_m\n"; 13205ffd83dbSDimitry Andric OS << "#define svcvtnt_bf16_f32_x svcvtnt_bf16_f32_m\n"; 13215ffd83dbSDimitry Andric 13225ffd83dbSDimitry Andric OS << "#define svcvtnt_f16_x svcvtnt_f16_m\n"; 13235ffd83dbSDimitry Andric OS << "#define svcvtnt_f16_f32_x svcvtnt_f16_f32_m\n"; 13245ffd83dbSDimitry Andric OS << "#define svcvtnt_f32_x svcvtnt_f32_m\n"; 13255ffd83dbSDimitry Andric OS << "#define svcvtnt_f32_f64_x svcvtnt_f32_f64_m\n\n"; 13265ffd83dbSDimitry Andric 13275ffd83dbSDimitry Andric OS << "#define svcvtxnt_f32_x svcvtxnt_f32_m\n"; 13285ffd83dbSDimitry Andric OS << "#define svcvtxnt_f32_f64_x svcvtxnt_f32_f64_m\n\n"; 13295ffd83dbSDimitry Andric 13305ffd83dbSDimitry Andric OS << "#ifdef __cplusplus\n"; 13315ffd83dbSDimitry Andric OS << "} // extern \"C\"\n"; 13325ffd83dbSDimitry Andric OS << "#endif\n\n"; 1333a4a491e2SDimitry Andric OS << "#undef __ai\n\n"; 1334a4a491e2SDimitry Andric OS << "#undef __aio\n\n"; 13355ffd83dbSDimitry Andric OS << "#endif /* __ARM_SVE_H */\n"; 13365ffd83dbSDimitry Andric } 13375ffd83dbSDimitry Andric 13385ffd83dbSDimitry Andric void SVEEmitter::createBuiltins(raw_ostream &OS) { 13395ffd83dbSDimitry Andric std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 13405ffd83dbSDimitry Andric SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 13415ffd83dbSDimitry Andric for (auto *R : RV) 13425ffd83dbSDimitry Andric createIntrinsic(R, Defs); 13435ffd83dbSDimitry Andric 13445ffd83dbSDimitry Andric // The mappings must be sorted based on BuiltinID. 13455ffd83dbSDimitry Andric llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 13465ffd83dbSDimitry Andric const std::unique_ptr<Intrinsic> &B) { 13475ffd83dbSDimitry Andric return A->getMangledName() < B->getMangledName(); 13485ffd83dbSDimitry Andric }); 13495ffd83dbSDimitry Andric 13505ffd83dbSDimitry Andric OS << "#ifdef GET_SVE_BUILTINS\n"; 13515ffd83dbSDimitry Andric for (auto &Def : Defs) { 13525ffd83dbSDimitry Andric // Only create BUILTINs for non-overloaded intrinsics, as overloaded 13535ffd83dbSDimitry Andric // declarations only live in the header file. 13545ffd83dbSDimitry Andric if (Def->getClassKind() != ClassG) 1355bdd1243dSDimitry Andric OS << "TARGET_BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \"" 1356bdd1243dSDimitry Andric << Def->getBuiltinTypeStr() << "\", \"n\", \"" << Def->getGuard() 1357bdd1243dSDimitry Andric << "\")\n"; 13585ffd83dbSDimitry Andric } 13595ffd83dbSDimitry Andric 13605ffd83dbSDimitry Andric // Add reinterpret builtins 13615ffd83dbSDimitry Andric for (const ReinterpretTypeInfo &From : Reinterprets) 13625ffd83dbSDimitry Andric for (const ReinterpretTypeInfo &To : Reinterprets) 1363bdd1243dSDimitry Andric OS << "TARGET_BUILTIN(__builtin_sve_reinterpret_" << From.Suffix << "_" 13645ffd83dbSDimitry Andric << To.Suffix << +", \"" << From.BuiltinType << To.BuiltinType 1365bdd1243dSDimitry Andric << "\", \"n\", \"sve\")\n"; 13665ffd83dbSDimitry Andric 13675ffd83dbSDimitry Andric OS << "#endif\n\n"; 13685ffd83dbSDimitry Andric } 13695ffd83dbSDimitry Andric 13705ffd83dbSDimitry Andric void SVEEmitter::createCodeGenMap(raw_ostream &OS) { 13715ffd83dbSDimitry Andric std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 13725ffd83dbSDimitry Andric SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 13735ffd83dbSDimitry Andric for (auto *R : RV) 13745ffd83dbSDimitry Andric createIntrinsic(R, Defs); 13755ffd83dbSDimitry Andric 13765ffd83dbSDimitry Andric // The mappings must be sorted based on BuiltinID. 13775ffd83dbSDimitry Andric llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 13785ffd83dbSDimitry Andric const std::unique_ptr<Intrinsic> &B) { 13795ffd83dbSDimitry Andric return A->getMangledName() < B->getMangledName(); 13805ffd83dbSDimitry Andric }); 13815ffd83dbSDimitry Andric 13825ffd83dbSDimitry Andric OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n"; 13835ffd83dbSDimitry Andric for (auto &Def : Defs) { 13845ffd83dbSDimitry Andric // Builtins only exist for non-overloaded intrinsics, overloaded 13855ffd83dbSDimitry Andric // declarations only live in the header file. 13865ffd83dbSDimitry Andric if (Def->getClassKind() == ClassG) 13875ffd83dbSDimitry Andric continue; 13885ffd83dbSDimitry Andric 13895ffd83dbSDimitry Andric uint64_t Flags = Def->getFlags(); 13905ffd83dbSDimitry Andric auto FlagString = std::to_string(Flags); 13915ffd83dbSDimitry Andric 1392*06c3fb27SDimitry Andric std::string LLVMName = Def->getMangledLLVMName(); 13935ffd83dbSDimitry Andric std::string Builtin = Def->getMangledName(); 13945ffd83dbSDimitry Andric if (!LLVMName.empty()) 13955ffd83dbSDimitry Andric OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString 13965ffd83dbSDimitry Andric << "),\n"; 13975ffd83dbSDimitry Andric else 13985ffd83dbSDimitry Andric OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n"; 13995ffd83dbSDimitry Andric } 14005ffd83dbSDimitry Andric OS << "#endif\n\n"; 14015ffd83dbSDimitry Andric } 14025ffd83dbSDimitry Andric 14035ffd83dbSDimitry Andric void SVEEmitter::createRangeChecks(raw_ostream &OS) { 14045ffd83dbSDimitry Andric std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 14055ffd83dbSDimitry Andric SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 14065ffd83dbSDimitry Andric for (auto *R : RV) 14075ffd83dbSDimitry Andric createIntrinsic(R, Defs); 14085ffd83dbSDimitry Andric 14095ffd83dbSDimitry Andric // The mappings must be sorted based on BuiltinID. 14105ffd83dbSDimitry Andric llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 14115ffd83dbSDimitry Andric const std::unique_ptr<Intrinsic> &B) { 14125ffd83dbSDimitry Andric return A->getMangledName() < B->getMangledName(); 14135ffd83dbSDimitry Andric }); 14145ffd83dbSDimitry Andric 14155ffd83dbSDimitry Andric 14165ffd83dbSDimitry Andric OS << "#ifdef GET_SVE_IMMEDIATE_CHECK\n"; 14175ffd83dbSDimitry Andric 14185ffd83dbSDimitry Andric // Ensure these are only emitted once. 14195ffd83dbSDimitry Andric std::set<std::string> Emitted; 14205ffd83dbSDimitry Andric 14215ffd83dbSDimitry Andric for (auto &Def : Defs) { 14225ffd83dbSDimitry Andric if (Emitted.find(Def->getMangledName()) != Emitted.end() || 14235ffd83dbSDimitry Andric Def->getImmChecks().empty()) 14245ffd83dbSDimitry Andric continue; 14255ffd83dbSDimitry Andric 14265ffd83dbSDimitry Andric OS << "case SVE::BI__builtin_sve_" << Def->getMangledName() << ":\n"; 14275ffd83dbSDimitry Andric for (auto &Check : Def->getImmChecks()) 14285ffd83dbSDimitry Andric OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", " 14295ffd83dbSDimitry Andric << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n"; 14305ffd83dbSDimitry Andric OS << " break;\n"; 14315ffd83dbSDimitry Andric 14325ffd83dbSDimitry Andric Emitted.insert(Def->getMangledName()); 14335ffd83dbSDimitry Andric } 14345ffd83dbSDimitry Andric 14355ffd83dbSDimitry Andric OS << "#endif\n\n"; 14365ffd83dbSDimitry Andric } 14375ffd83dbSDimitry Andric 14385ffd83dbSDimitry Andric /// Create the SVETypeFlags used in CGBuiltins 14395ffd83dbSDimitry Andric void SVEEmitter::createTypeFlags(raw_ostream &OS) { 14405ffd83dbSDimitry Andric OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n"; 14415ffd83dbSDimitry Andric for (auto &KV : FlagTypes) 14425ffd83dbSDimitry Andric OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n"; 14435ffd83dbSDimitry Andric OS << "#endif\n\n"; 14445ffd83dbSDimitry Andric 14455ffd83dbSDimitry Andric OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n"; 14465ffd83dbSDimitry Andric for (auto &KV : EltTypes) 14475ffd83dbSDimitry Andric OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; 14485ffd83dbSDimitry Andric OS << "#endif\n\n"; 14495ffd83dbSDimitry Andric 14505ffd83dbSDimitry Andric OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n"; 14515ffd83dbSDimitry Andric for (auto &KV : MemEltTypes) 14525ffd83dbSDimitry Andric OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; 14535ffd83dbSDimitry Andric OS << "#endif\n\n"; 14545ffd83dbSDimitry Andric 14555ffd83dbSDimitry Andric OS << "#ifdef LLVM_GET_SVE_MERGETYPES\n"; 14565ffd83dbSDimitry Andric for (auto &KV : MergeTypes) 14575ffd83dbSDimitry Andric OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; 14585ffd83dbSDimitry Andric OS << "#endif\n\n"; 14595ffd83dbSDimitry Andric 14605ffd83dbSDimitry Andric OS << "#ifdef LLVM_GET_SVE_IMMCHECKTYPES\n"; 14615ffd83dbSDimitry Andric for (auto &KV : ImmCheckTypes) 14625ffd83dbSDimitry Andric OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; 14635ffd83dbSDimitry Andric OS << "#endif\n\n"; 14645ffd83dbSDimitry Andric } 14655ffd83dbSDimitry Andric 1466*06c3fb27SDimitry Andric void SVEEmitter::createSMEHeader(raw_ostream &OS) { 1467*06c3fb27SDimitry Andric OS << "/*===---- arm_sme_draft_spec_subject_to_change.h - ARM SME intrinsics " 1468*06c3fb27SDimitry Andric "------===\n" 1469*06c3fb27SDimitry Andric " *\n" 1470*06c3fb27SDimitry Andric " *\n" 1471*06c3fb27SDimitry Andric " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " 1472*06c3fb27SDimitry Andric "Exceptions.\n" 1473*06c3fb27SDimitry Andric " * See https://llvm.org/LICENSE.txt for license information.\n" 1474*06c3fb27SDimitry Andric " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 1475*06c3fb27SDimitry Andric " *\n" 1476*06c3fb27SDimitry Andric " *===-----------------------------------------------------------------" 1477*06c3fb27SDimitry Andric "------===\n" 1478*06c3fb27SDimitry Andric " */\n\n"; 1479*06c3fb27SDimitry Andric 1480*06c3fb27SDimitry Andric OS << "#ifndef __ARM_SME_H\n"; 1481*06c3fb27SDimitry Andric OS << "#define __ARM_SME_H\n\n"; 1482*06c3fb27SDimitry Andric 1483*06c3fb27SDimitry Andric OS << "#if !defined(__LITTLE_ENDIAN__)\n"; 1484*06c3fb27SDimitry Andric OS << "#error \"Big endian is currently not supported for arm_sme_draft_spec_subject_to_change.h\"\n"; 1485*06c3fb27SDimitry Andric OS << "#endif\n"; 1486*06c3fb27SDimitry Andric 1487*06c3fb27SDimitry Andric OS << "#include <arm_sve.h> \n\n"; 1488*06c3fb27SDimitry Andric 1489*06c3fb27SDimitry Andric OS << "/* Function attributes */\n"; 1490*06c3fb27SDimitry Andric OS << "#define __ai static __inline__ __attribute__((__always_inline__, " 1491*06c3fb27SDimitry Andric "__nodebug__))\n\n"; 1492*06c3fb27SDimitry Andric OS << "#define __aio static __inline__ __attribute__((__always_inline__, " 1493*06c3fb27SDimitry Andric "__nodebug__, __overloadable__))\n\n"; 1494*06c3fb27SDimitry Andric 1495*06c3fb27SDimitry Andric OS << "#ifdef __cplusplus\n"; 1496*06c3fb27SDimitry Andric OS << "extern \"C\" {\n"; 1497*06c3fb27SDimitry Andric OS << "#endif\n\n"; 1498*06c3fb27SDimitry Andric 1499*06c3fb27SDimitry Andric SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 1500*06c3fb27SDimitry Andric std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 1501*06c3fb27SDimitry Andric for (auto *R : RV) 1502*06c3fb27SDimitry Andric createIntrinsic(R, Defs); 1503*06c3fb27SDimitry Andric 1504*06c3fb27SDimitry Andric // Sort intrinsics in header file by following order/priority similar to SVE: 1505*06c3fb27SDimitry Andric // - Architectural guard 1506*06c3fb27SDimitry Andric // - Class (is intrinsic overloaded or not) 1507*06c3fb27SDimitry Andric // - Intrinsic name 1508*06c3fb27SDimitry Andric std::stable_sort(Defs.begin(), Defs.end(), 1509*06c3fb27SDimitry Andric [](const std::unique_ptr<Intrinsic> &A, 1510*06c3fb27SDimitry Andric const std::unique_ptr<Intrinsic> &B) { 1511*06c3fb27SDimitry Andric auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) { 1512*06c3fb27SDimitry Andric return std::make_tuple(I->getGuard(), 1513*06c3fb27SDimitry Andric (unsigned)I->getClassKind(), 1514*06c3fb27SDimitry Andric I->getName()); 1515*06c3fb27SDimitry Andric }; 1516*06c3fb27SDimitry Andric return ToTuple(A) < ToTuple(B); 1517*06c3fb27SDimitry Andric }); 1518*06c3fb27SDimitry Andric 1519*06c3fb27SDimitry Andric // Actually emit the intrinsic declaration. 1520*06c3fb27SDimitry Andric for (auto &I : Defs) { 1521*06c3fb27SDimitry Andric I->emitIntrinsic(OS, *this); 1522*06c3fb27SDimitry Andric } 1523*06c3fb27SDimitry Andric 1524*06c3fb27SDimitry Andric OS << "#ifdef __cplusplus\n"; 1525*06c3fb27SDimitry Andric OS << "} // extern \"C\"\n"; 1526*06c3fb27SDimitry Andric OS << "#endif\n\n"; 1527*06c3fb27SDimitry Andric OS << "#undef __ai\n\n"; 1528*06c3fb27SDimitry Andric OS << "#endif /* __ARM_SME_H */\n"; 1529*06c3fb27SDimitry Andric } 1530*06c3fb27SDimitry Andric 1531*06c3fb27SDimitry Andric void SVEEmitter::createSMEBuiltins(raw_ostream &OS) { 1532*06c3fb27SDimitry Andric std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 1533*06c3fb27SDimitry Andric SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 1534*06c3fb27SDimitry Andric for (auto *R : RV) { 1535*06c3fb27SDimitry Andric createIntrinsic(R, Defs); 1536*06c3fb27SDimitry Andric } 1537*06c3fb27SDimitry Andric 1538*06c3fb27SDimitry Andric // The mappings must be sorted based on BuiltinID. 1539*06c3fb27SDimitry Andric llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 1540*06c3fb27SDimitry Andric const std::unique_ptr<Intrinsic> &B) { 1541*06c3fb27SDimitry Andric return A->getMangledName() < B->getMangledName(); 1542*06c3fb27SDimitry Andric }); 1543*06c3fb27SDimitry Andric 1544*06c3fb27SDimitry Andric OS << "#ifdef GET_SME_BUILTINS\n"; 1545*06c3fb27SDimitry Andric for (auto &Def : Defs) { 1546*06c3fb27SDimitry Andric // Only create BUILTINs for non-overloaded intrinsics, as overloaded 1547*06c3fb27SDimitry Andric // declarations only live in the header file. 1548*06c3fb27SDimitry Andric if (Def->getClassKind() != ClassG) 1549*06c3fb27SDimitry Andric OS << "TARGET_BUILTIN(__builtin_sme_" << Def->getMangledName() << ", \"" 1550*06c3fb27SDimitry Andric << Def->getBuiltinTypeStr() << "\", \"n\", \"" << Def->getGuard() 1551*06c3fb27SDimitry Andric << "\")\n"; 1552*06c3fb27SDimitry Andric } 1553*06c3fb27SDimitry Andric 1554*06c3fb27SDimitry Andric OS << "#endif\n\n"; 1555*06c3fb27SDimitry Andric } 1556*06c3fb27SDimitry Andric 1557*06c3fb27SDimitry Andric void SVEEmitter::createSMECodeGenMap(raw_ostream &OS) { 1558*06c3fb27SDimitry Andric std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 1559*06c3fb27SDimitry Andric SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 1560*06c3fb27SDimitry Andric for (auto *R : RV) { 1561*06c3fb27SDimitry Andric createIntrinsic(R, Defs); 1562*06c3fb27SDimitry Andric } 1563*06c3fb27SDimitry Andric 1564*06c3fb27SDimitry Andric // The mappings must be sorted based on BuiltinID. 1565*06c3fb27SDimitry Andric llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 1566*06c3fb27SDimitry Andric const std::unique_ptr<Intrinsic> &B) { 1567*06c3fb27SDimitry Andric return A->getMangledName() < B->getMangledName(); 1568*06c3fb27SDimitry Andric }); 1569*06c3fb27SDimitry Andric 1570*06c3fb27SDimitry Andric OS << "#ifdef GET_SME_LLVM_INTRINSIC_MAP\n"; 1571*06c3fb27SDimitry Andric for (auto &Def : Defs) { 1572*06c3fb27SDimitry Andric // Builtins only exist for non-overloaded intrinsics, overloaded 1573*06c3fb27SDimitry Andric // declarations only live in the header file. 1574*06c3fb27SDimitry Andric if (Def->getClassKind() == ClassG) 1575*06c3fb27SDimitry Andric continue; 1576*06c3fb27SDimitry Andric 1577*06c3fb27SDimitry Andric uint64_t Flags = Def->getFlags(); 1578*06c3fb27SDimitry Andric auto FlagString = std::to_string(Flags); 1579*06c3fb27SDimitry Andric 1580*06c3fb27SDimitry Andric std::string LLVMName = Def->getLLVMName(); 1581*06c3fb27SDimitry Andric std::string Builtin = Def->getMangledName(); 1582*06c3fb27SDimitry Andric if (!LLVMName.empty()) 1583*06c3fb27SDimitry Andric OS << "SMEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString 1584*06c3fb27SDimitry Andric << "),\n"; 1585*06c3fb27SDimitry Andric else 1586*06c3fb27SDimitry Andric OS << "SMEMAP2(" << Builtin << ", " << FlagString << "),\n"; 1587*06c3fb27SDimitry Andric } 1588*06c3fb27SDimitry Andric OS << "#endif\n\n"; 1589*06c3fb27SDimitry Andric } 1590*06c3fb27SDimitry Andric 1591*06c3fb27SDimitry Andric void SVEEmitter::createSMERangeChecks(raw_ostream &OS) { 1592*06c3fb27SDimitry Andric std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 1593*06c3fb27SDimitry Andric SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 1594*06c3fb27SDimitry Andric for (auto *R : RV) { 1595*06c3fb27SDimitry Andric createIntrinsic(R, Defs); 1596*06c3fb27SDimitry Andric } 1597*06c3fb27SDimitry Andric 1598*06c3fb27SDimitry Andric // The mappings must be sorted based on BuiltinID. 1599*06c3fb27SDimitry Andric llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 1600*06c3fb27SDimitry Andric const std::unique_ptr<Intrinsic> &B) { 1601*06c3fb27SDimitry Andric return A->getMangledName() < B->getMangledName(); 1602*06c3fb27SDimitry Andric }); 1603*06c3fb27SDimitry Andric 1604*06c3fb27SDimitry Andric 1605*06c3fb27SDimitry Andric OS << "#ifdef GET_SME_IMMEDIATE_CHECK\n"; 1606*06c3fb27SDimitry Andric 1607*06c3fb27SDimitry Andric // Ensure these are only emitted once. 1608*06c3fb27SDimitry Andric std::set<std::string> Emitted; 1609*06c3fb27SDimitry Andric 1610*06c3fb27SDimitry Andric for (auto &Def : Defs) { 1611*06c3fb27SDimitry Andric if (Emitted.find(Def->getMangledName()) != Emitted.end() || 1612*06c3fb27SDimitry Andric Def->getImmChecks().empty()) 1613*06c3fb27SDimitry Andric continue; 1614*06c3fb27SDimitry Andric 1615*06c3fb27SDimitry Andric OS << "case SME::BI__builtin_sme_" << Def->getMangledName() << ":\n"; 1616*06c3fb27SDimitry Andric for (auto &Check : Def->getImmChecks()) 1617*06c3fb27SDimitry Andric OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", " 1618*06c3fb27SDimitry Andric << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n"; 1619*06c3fb27SDimitry Andric OS << " break;\n"; 1620*06c3fb27SDimitry Andric 1621*06c3fb27SDimitry Andric Emitted.insert(Def->getMangledName()); 1622*06c3fb27SDimitry Andric } 1623*06c3fb27SDimitry Andric 1624*06c3fb27SDimitry Andric OS << "#endif\n\n"; 1625*06c3fb27SDimitry Andric } 1626*06c3fb27SDimitry Andric 16275ffd83dbSDimitry Andric namespace clang { 16285ffd83dbSDimitry Andric void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) { 16295ffd83dbSDimitry Andric SVEEmitter(Records).createHeader(OS); 16305ffd83dbSDimitry Andric } 16315ffd83dbSDimitry Andric 16325ffd83dbSDimitry Andric void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) { 16335ffd83dbSDimitry Andric SVEEmitter(Records).createBuiltins(OS); 16345ffd83dbSDimitry Andric } 16355ffd83dbSDimitry Andric 16365ffd83dbSDimitry Andric void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 16375ffd83dbSDimitry Andric SVEEmitter(Records).createCodeGenMap(OS); 16385ffd83dbSDimitry Andric } 16395ffd83dbSDimitry Andric 16405ffd83dbSDimitry Andric void EmitSveRangeChecks(RecordKeeper &Records, raw_ostream &OS) { 16415ffd83dbSDimitry Andric SVEEmitter(Records).createRangeChecks(OS); 16425ffd83dbSDimitry Andric } 16435ffd83dbSDimitry Andric 16445ffd83dbSDimitry Andric void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) { 16455ffd83dbSDimitry Andric SVEEmitter(Records).createTypeFlags(OS); 16465ffd83dbSDimitry Andric } 16475ffd83dbSDimitry Andric 1648*06c3fb27SDimitry Andric void EmitSmeHeader(RecordKeeper &Records, raw_ostream &OS) { 1649*06c3fb27SDimitry Andric SVEEmitter(Records).createSMEHeader(OS); 1650*06c3fb27SDimitry Andric } 1651*06c3fb27SDimitry Andric 1652*06c3fb27SDimitry Andric void EmitSmeBuiltins(RecordKeeper &Records, raw_ostream &OS) { 1653*06c3fb27SDimitry Andric SVEEmitter(Records).createSMEBuiltins(OS); 1654*06c3fb27SDimitry Andric } 1655*06c3fb27SDimitry Andric 1656*06c3fb27SDimitry Andric void EmitSmeBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 1657*06c3fb27SDimitry Andric SVEEmitter(Records).createSMECodeGenMap(OS); 1658*06c3fb27SDimitry Andric } 1659*06c3fb27SDimitry Andric 1660*06c3fb27SDimitry Andric void EmitSmeRangeChecks(RecordKeeper &Records, raw_ostream &OS) { 1661*06c3fb27SDimitry Andric SVEEmitter(Records).createSMERangeChecks(OS); 1662*06c3fb27SDimitry Andric } 16635ffd83dbSDimitry Andric } // End namespace clang 1664