1*5ffd83dbSDimitry Andric //===- SveEmitter.cpp - Generate arm_sve.h for use with clang -*- C++ -*-===// 2*5ffd83dbSDimitry Andric // 3*5ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*5ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*5ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*5ffd83dbSDimitry Andric // 7*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 8*5ffd83dbSDimitry Andric // 9*5ffd83dbSDimitry Andric // This tablegen backend is responsible for emitting arm_sve.h, which includes 10*5ffd83dbSDimitry Andric // a declaration and definition of each function specified by the ARM C/C++ 11*5ffd83dbSDimitry Andric // Language Extensions (ACLE). 12*5ffd83dbSDimitry Andric // 13*5ffd83dbSDimitry Andric // For details, visit: 14*5ffd83dbSDimitry Andric // https://developer.arm.com/architectures/system-architectures/software-standards/acle 15*5ffd83dbSDimitry Andric // 16*5ffd83dbSDimitry Andric // Each SVE instruction is implemented in terms of 1 or more functions which 17*5ffd83dbSDimitry Andric // are suffixed with the element type of the input vectors. Functions may be 18*5ffd83dbSDimitry Andric // implemented in terms of generic vector operations such as +, *, -, etc. or 19*5ffd83dbSDimitry Andric // by calling a __builtin_-prefixed function which will be handled by clang's 20*5ffd83dbSDimitry Andric // CodeGen library. 21*5ffd83dbSDimitry Andric // 22*5ffd83dbSDimitry Andric // See also the documentation in include/clang/Basic/arm_sve.td. 23*5ffd83dbSDimitry Andric // 24*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 25*5ffd83dbSDimitry Andric 26*5ffd83dbSDimitry Andric #include "llvm/ADT/STLExtras.h" 27*5ffd83dbSDimitry Andric #include "llvm/ADT/StringMap.h" 28*5ffd83dbSDimitry Andric #include "llvm/ADT/ArrayRef.h" 29*5ffd83dbSDimitry Andric #include "llvm/ADT/StringExtras.h" 30*5ffd83dbSDimitry Andric #include "llvm/TableGen/Record.h" 31*5ffd83dbSDimitry Andric #include "llvm/TableGen/Error.h" 32*5ffd83dbSDimitry Andric #include <string> 33*5ffd83dbSDimitry Andric #include <sstream> 34*5ffd83dbSDimitry Andric #include <set> 35*5ffd83dbSDimitry Andric #include <cctype> 36*5ffd83dbSDimitry Andric #include <tuple> 37*5ffd83dbSDimitry Andric 38*5ffd83dbSDimitry Andric using namespace llvm; 39*5ffd83dbSDimitry Andric 40*5ffd83dbSDimitry Andric enum ClassKind { 41*5ffd83dbSDimitry Andric ClassNone, 42*5ffd83dbSDimitry Andric ClassS, // signed/unsigned, e.g., "_s8", "_u8" suffix 43*5ffd83dbSDimitry Andric ClassG, // Overloaded name without type suffix 44*5ffd83dbSDimitry Andric }; 45*5ffd83dbSDimitry Andric 46*5ffd83dbSDimitry Andric using TypeSpec = std::string; 47*5ffd83dbSDimitry Andric 48*5ffd83dbSDimitry Andric namespace { 49*5ffd83dbSDimitry Andric 50*5ffd83dbSDimitry Andric class ImmCheck { 51*5ffd83dbSDimitry Andric unsigned Arg; 52*5ffd83dbSDimitry Andric unsigned Kind; 53*5ffd83dbSDimitry Andric unsigned ElementSizeInBits; 54*5ffd83dbSDimitry Andric 55*5ffd83dbSDimitry Andric public: 56*5ffd83dbSDimitry Andric ImmCheck(unsigned Arg, unsigned Kind, unsigned ElementSizeInBits = 0) 57*5ffd83dbSDimitry Andric : Arg(Arg), Kind(Kind), ElementSizeInBits(ElementSizeInBits) {} 58*5ffd83dbSDimitry Andric ImmCheck(const ImmCheck &Other) = default; 59*5ffd83dbSDimitry Andric ~ImmCheck() = default; 60*5ffd83dbSDimitry Andric 61*5ffd83dbSDimitry Andric unsigned getArg() const { return Arg; } 62*5ffd83dbSDimitry Andric unsigned getKind() const { return Kind; } 63*5ffd83dbSDimitry Andric unsigned getElementSizeInBits() const { return ElementSizeInBits; } 64*5ffd83dbSDimitry Andric }; 65*5ffd83dbSDimitry Andric 66*5ffd83dbSDimitry Andric class SVEType { 67*5ffd83dbSDimitry Andric TypeSpec TS; 68*5ffd83dbSDimitry Andric bool Float, Signed, Immediate, Void, Constant, Pointer, BFloat; 69*5ffd83dbSDimitry Andric bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp; 70*5ffd83dbSDimitry Andric unsigned Bitwidth, ElementBitwidth, NumVectors; 71*5ffd83dbSDimitry Andric 72*5ffd83dbSDimitry Andric public: 73*5ffd83dbSDimitry Andric SVEType() : SVEType(TypeSpec(), 'v') {} 74*5ffd83dbSDimitry Andric 75*5ffd83dbSDimitry Andric SVEType(TypeSpec TS, char CharMod) 76*5ffd83dbSDimitry Andric : TS(TS), Float(false), Signed(true), Immediate(false), Void(false), 77*5ffd83dbSDimitry Andric Constant(false), Pointer(false), BFloat(false), DefaultType(false), 78*5ffd83dbSDimitry Andric IsScalable(true), Predicate(false), PredicatePattern(false), 79*5ffd83dbSDimitry Andric PrefetchOp(false), Bitwidth(128), ElementBitwidth(~0U), NumVectors(1) { 80*5ffd83dbSDimitry Andric if (!TS.empty()) 81*5ffd83dbSDimitry Andric applyTypespec(); 82*5ffd83dbSDimitry Andric applyModifier(CharMod); 83*5ffd83dbSDimitry Andric } 84*5ffd83dbSDimitry Andric 85*5ffd83dbSDimitry Andric bool isPointer() const { return Pointer; } 86*5ffd83dbSDimitry Andric bool isVoidPointer() const { return Pointer && Void; } 87*5ffd83dbSDimitry Andric bool isSigned() const { return Signed; } 88*5ffd83dbSDimitry Andric bool isImmediate() const { return Immediate; } 89*5ffd83dbSDimitry Andric bool isScalar() const { return NumVectors == 0; } 90*5ffd83dbSDimitry Andric bool isVector() const { return NumVectors > 0; } 91*5ffd83dbSDimitry Andric bool isScalableVector() const { return isVector() && IsScalable; } 92*5ffd83dbSDimitry Andric bool isChar() const { return ElementBitwidth == 8; } 93*5ffd83dbSDimitry Andric bool isVoid() const { return Void & !Pointer; } 94*5ffd83dbSDimitry Andric bool isDefault() const { return DefaultType; } 95*5ffd83dbSDimitry Andric bool isFloat() const { return Float && !BFloat; } 96*5ffd83dbSDimitry Andric bool isBFloat() const { return BFloat && !Float; } 97*5ffd83dbSDimitry Andric bool isFloatingPoint() const { return Float || BFloat; } 98*5ffd83dbSDimitry Andric bool isInteger() const { return !isFloatingPoint() && !Predicate; } 99*5ffd83dbSDimitry Andric bool isScalarPredicate() const { 100*5ffd83dbSDimitry Andric return !isFloatingPoint() && Predicate && NumVectors == 0; 101*5ffd83dbSDimitry Andric } 102*5ffd83dbSDimitry Andric bool isPredicateVector() const { return Predicate; } 103*5ffd83dbSDimitry Andric bool isPredicatePattern() const { return PredicatePattern; } 104*5ffd83dbSDimitry Andric bool isPrefetchOp() const { return PrefetchOp; } 105*5ffd83dbSDimitry Andric bool isConstant() const { return Constant; } 106*5ffd83dbSDimitry Andric unsigned getElementSizeInBits() const { return ElementBitwidth; } 107*5ffd83dbSDimitry Andric unsigned getNumVectors() const { return NumVectors; } 108*5ffd83dbSDimitry Andric 109*5ffd83dbSDimitry Andric unsigned getNumElements() const { 110*5ffd83dbSDimitry Andric assert(ElementBitwidth != ~0U); 111*5ffd83dbSDimitry Andric return Bitwidth / ElementBitwidth; 112*5ffd83dbSDimitry Andric } 113*5ffd83dbSDimitry Andric unsigned getSizeInBits() const { 114*5ffd83dbSDimitry Andric return Bitwidth; 115*5ffd83dbSDimitry Andric } 116*5ffd83dbSDimitry Andric 117*5ffd83dbSDimitry Andric /// Return the string representation of a type, which is an encoded 118*5ffd83dbSDimitry Andric /// string for passing to the BUILTIN() macro in Builtins.def. 119*5ffd83dbSDimitry Andric std::string builtin_str() const; 120*5ffd83dbSDimitry Andric 121*5ffd83dbSDimitry Andric /// Return the C/C++ string representation of a type for use in the 122*5ffd83dbSDimitry Andric /// arm_sve.h header file. 123*5ffd83dbSDimitry Andric std::string str() const; 124*5ffd83dbSDimitry Andric 125*5ffd83dbSDimitry Andric private: 126*5ffd83dbSDimitry Andric /// Creates the type based on the typespec string in TS. 127*5ffd83dbSDimitry Andric void applyTypespec(); 128*5ffd83dbSDimitry Andric 129*5ffd83dbSDimitry Andric /// Applies a prototype modifier to the type. 130*5ffd83dbSDimitry Andric void applyModifier(char Mod); 131*5ffd83dbSDimitry Andric }; 132*5ffd83dbSDimitry Andric 133*5ffd83dbSDimitry Andric 134*5ffd83dbSDimitry Andric class SVEEmitter; 135*5ffd83dbSDimitry Andric 136*5ffd83dbSDimitry Andric /// The main grunt class. This represents an instantiation of an intrinsic with 137*5ffd83dbSDimitry Andric /// a particular typespec and prototype. 138*5ffd83dbSDimitry Andric class Intrinsic { 139*5ffd83dbSDimitry Andric /// The unmangled name. 140*5ffd83dbSDimitry Andric std::string Name; 141*5ffd83dbSDimitry Andric 142*5ffd83dbSDimitry Andric /// The name of the corresponding LLVM IR intrinsic. 143*5ffd83dbSDimitry Andric std::string LLVMName; 144*5ffd83dbSDimitry Andric 145*5ffd83dbSDimitry Andric /// Intrinsic prototype. 146*5ffd83dbSDimitry Andric std::string Proto; 147*5ffd83dbSDimitry Andric 148*5ffd83dbSDimitry Andric /// The base type spec for this intrinsic. 149*5ffd83dbSDimitry Andric TypeSpec BaseTypeSpec; 150*5ffd83dbSDimitry Andric 151*5ffd83dbSDimitry Andric /// The base class kind. Most intrinsics use ClassS, which has full type 152*5ffd83dbSDimitry Andric /// info for integers (_s32/_u32), or ClassG which is used for overloaded 153*5ffd83dbSDimitry Andric /// intrinsics. 154*5ffd83dbSDimitry Andric ClassKind Class; 155*5ffd83dbSDimitry Andric 156*5ffd83dbSDimitry Andric /// The architectural #ifdef guard. 157*5ffd83dbSDimitry Andric std::string Guard; 158*5ffd83dbSDimitry Andric 159*5ffd83dbSDimitry Andric // The merge suffix such as _m, _x or _z. 160*5ffd83dbSDimitry Andric std::string MergeSuffix; 161*5ffd83dbSDimitry Andric 162*5ffd83dbSDimitry Andric /// The types of return value [0] and parameters [1..]. 163*5ffd83dbSDimitry Andric std::vector<SVEType> Types; 164*5ffd83dbSDimitry Andric 165*5ffd83dbSDimitry Andric /// The "base type", which is VarType('d', BaseTypeSpec). 166*5ffd83dbSDimitry Andric SVEType BaseType; 167*5ffd83dbSDimitry Andric 168*5ffd83dbSDimitry Andric uint64_t Flags; 169*5ffd83dbSDimitry Andric 170*5ffd83dbSDimitry Andric SmallVector<ImmCheck, 2> ImmChecks; 171*5ffd83dbSDimitry Andric 172*5ffd83dbSDimitry Andric public: 173*5ffd83dbSDimitry Andric Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy, 174*5ffd83dbSDimitry Andric StringRef MergeSuffix, uint64_t MemoryElementTy, StringRef LLVMName, 175*5ffd83dbSDimitry Andric uint64_t Flags, ArrayRef<ImmCheck> ImmChecks, TypeSpec BT, 176*5ffd83dbSDimitry Andric ClassKind Class, SVEEmitter &Emitter, StringRef Guard); 177*5ffd83dbSDimitry Andric 178*5ffd83dbSDimitry Andric ~Intrinsic()=default; 179*5ffd83dbSDimitry Andric 180*5ffd83dbSDimitry Andric std::string getName() const { return Name; } 181*5ffd83dbSDimitry Andric std::string getLLVMName() const { return LLVMName; } 182*5ffd83dbSDimitry Andric std::string getProto() const { return Proto; } 183*5ffd83dbSDimitry Andric TypeSpec getBaseTypeSpec() const { return BaseTypeSpec; } 184*5ffd83dbSDimitry Andric SVEType getBaseType() const { return BaseType; } 185*5ffd83dbSDimitry Andric 186*5ffd83dbSDimitry Andric StringRef getGuard() const { return Guard; } 187*5ffd83dbSDimitry Andric ClassKind getClassKind() const { return Class; } 188*5ffd83dbSDimitry Andric 189*5ffd83dbSDimitry Andric SVEType getReturnType() const { return Types[0]; } 190*5ffd83dbSDimitry Andric ArrayRef<SVEType> getTypes() const { return Types; } 191*5ffd83dbSDimitry Andric SVEType getParamType(unsigned I) const { return Types[I + 1]; } 192*5ffd83dbSDimitry Andric unsigned getNumParams() const { return Proto.size() - 1; } 193*5ffd83dbSDimitry Andric 194*5ffd83dbSDimitry Andric uint64_t getFlags() const { return Flags; } 195*5ffd83dbSDimitry Andric bool isFlagSet(uint64_t Flag) const { return Flags & Flag;} 196*5ffd83dbSDimitry Andric 197*5ffd83dbSDimitry Andric ArrayRef<ImmCheck> getImmChecks() const { return ImmChecks; } 198*5ffd83dbSDimitry Andric 199*5ffd83dbSDimitry Andric /// Return the type string for a BUILTIN() macro in Builtins.def. 200*5ffd83dbSDimitry Andric std::string getBuiltinTypeStr(); 201*5ffd83dbSDimitry Andric 202*5ffd83dbSDimitry Andric /// Return the name, mangled with type information. The name is mangled for 203*5ffd83dbSDimitry Andric /// ClassS, so will add type suffixes such as _u32/_s32. 204*5ffd83dbSDimitry Andric std::string getMangledName() const { return mangleName(ClassS); } 205*5ffd83dbSDimitry Andric 206*5ffd83dbSDimitry Andric /// Returns true if the intrinsic is overloaded, in that it should also generate 207*5ffd83dbSDimitry Andric /// a short form without the type-specifiers, e.g. 'svld1(..)' instead of 208*5ffd83dbSDimitry Andric /// 'svld1_u32(..)'. 209*5ffd83dbSDimitry Andric static bool isOverloadedIntrinsic(StringRef Name) { 210*5ffd83dbSDimitry Andric auto BrOpen = Name.find("["); 211*5ffd83dbSDimitry Andric auto BrClose = Name.find(']'); 212*5ffd83dbSDimitry Andric return BrOpen != std::string::npos && BrClose != std::string::npos; 213*5ffd83dbSDimitry Andric } 214*5ffd83dbSDimitry Andric 215*5ffd83dbSDimitry Andric /// Return true if the intrinsic takes a splat operand. 216*5ffd83dbSDimitry Andric bool hasSplat() const { 217*5ffd83dbSDimitry Andric // These prototype modifiers are described in arm_sve.td. 218*5ffd83dbSDimitry Andric return Proto.find_first_of("ajfrKLR@") != std::string::npos; 219*5ffd83dbSDimitry Andric } 220*5ffd83dbSDimitry Andric 221*5ffd83dbSDimitry Andric /// Return the parameter index of the splat operand. 222*5ffd83dbSDimitry Andric unsigned getSplatIdx() const { 223*5ffd83dbSDimitry Andric // These prototype modifiers are described in arm_sve.td. 224*5ffd83dbSDimitry Andric auto Idx = Proto.find_first_of("ajfrKLR@"); 225*5ffd83dbSDimitry Andric assert(Idx != std::string::npos && Idx > 0 && 226*5ffd83dbSDimitry Andric "Prototype has no splat operand"); 227*5ffd83dbSDimitry Andric return Idx - 1; 228*5ffd83dbSDimitry Andric } 229*5ffd83dbSDimitry Andric 230*5ffd83dbSDimitry Andric /// Emits the intrinsic declaration to the ostream. 231*5ffd83dbSDimitry Andric void emitIntrinsic(raw_ostream &OS) const; 232*5ffd83dbSDimitry Andric 233*5ffd83dbSDimitry Andric private: 234*5ffd83dbSDimitry Andric std::string getMergeSuffix() const { return MergeSuffix; } 235*5ffd83dbSDimitry Andric std::string mangleName(ClassKind LocalCK) const; 236*5ffd83dbSDimitry Andric std::string replaceTemplatedArgs(std::string Name, TypeSpec TS, 237*5ffd83dbSDimitry Andric std::string Proto) const; 238*5ffd83dbSDimitry Andric }; 239*5ffd83dbSDimitry Andric 240*5ffd83dbSDimitry Andric class SVEEmitter { 241*5ffd83dbSDimitry Andric private: 242*5ffd83dbSDimitry Andric // The reinterpret builtins are generated separately because they 243*5ffd83dbSDimitry Andric // need the cross product of all types (121 functions in total), 244*5ffd83dbSDimitry Andric // which is inconvenient to specify in the arm_sve.td file or 245*5ffd83dbSDimitry Andric // generate in CGBuiltin.cpp. 246*5ffd83dbSDimitry Andric struct ReinterpretTypeInfo { 247*5ffd83dbSDimitry Andric const char *Suffix; 248*5ffd83dbSDimitry Andric const char *Type; 249*5ffd83dbSDimitry Andric const char *BuiltinType; 250*5ffd83dbSDimitry Andric }; 251*5ffd83dbSDimitry Andric SmallVector<ReinterpretTypeInfo, 12> Reinterprets = { 252*5ffd83dbSDimitry Andric {"s8", "svint8_t", "q16Sc"}, {"s16", "svint16_t", "q8Ss"}, 253*5ffd83dbSDimitry Andric {"s32", "svint32_t", "q4Si"}, {"s64", "svint64_t", "q2SWi"}, 254*5ffd83dbSDimitry Andric {"u8", "svuint8_t", "q16Uc"}, {"u16", "svuint16_t", "q8Us"}, 255*5ffd83dbSDimitry Andric {"u32", "svuint32_t", "q4Ui"}, {"u64", "svuint64_t", "q2UWi"}, 256*5ffd83dbSDimitry Andric {"f16", "svfloat16_t", "q8h"}, {"bf16", "svbfloat16_t", "q8y"}, 257*5ffd83dbSDimitry Andric {"f32", "svfloat32_t", "q4f"}, {"f64", "svfloat64_t", "q2d"}}; 258*5ffd83dbSDimitry Andric 259*5ffd83dbSDimitry Andric RecordKeeper &Records; 260*5ffd83dbSDimitry Andric llvm::StringMap<uint64_t> EltTypes; 261*5ffd83dbSDimitry Andric llvm::StringMap<uint64_t> MemEltTypes; 262*5ffd83dbSDimitry Andric llvm::StringMap<uint64_t> FlagTypes; 263*5ffd83dbSDimitry Andric llvm::StringMap<uint64_t> MergeTypes; 264*5ffd83dbSDimitry Andric llvm::StringMap<uint64_t> ImmCheckTypes; 265*5ffd83dbSDimitry Andric 266*5ffd83dbSDimitry Andric public: 267*5ffd83dbSDimitry Andric SVEEmitter(RecordKeeper &R) : Records(R) { 268*5ffd83dbSDimitry Andric for (auto *RV : Records.getAllDerivedDefinitions("EltType")) 269*5ffd83dbSDimitry Andric EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 270*5ffd83dbSDimitry Andric for (auto *RV : Records.getAllDerivedDefinitions("MemEltType")) 271*5ffd83dbSDimitry Andric MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 272*5ffd83dbSDimitry Andric for (auto *RV : Records.getAllDerivedDefinitions("FlagType")) 273*5ffd83dbSDimitry Andric FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 274*5ffd83dbSDimitry Andric for (auto *RV : Records.getAllDerivedDefinitions("MergeType")) 275*5ffd83dbSDimitry Andric MergeTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 276*5ffd83dbSDimitry Andric for (auto *RV : Records.getAllDerivedDefinitions("ImmCheckType")) 277*5ffd83dbSDimitry Andric ImmCheckTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); 278*5ffd83dbSDimitry Andric } 279*5ffd83dbSDimitry Andric 280*5ffd83dbSDimitry Andric /// Returns the enum value for the immcheck type 281*5ffd83dbSDimitry Andric unsigned getEnumValueForImmCheck(StringRef C) const { 282*5ffd83dbSDimitry Andric auto It = ImmCheckTypes.find(C); 283*5ffd83dbSDimitry Andric if (It != ImmCheckTypes.end()) 284*5ffd83dbSDimitry Andric return It->getValue(); 285*5ffd83dbSDimitry Andric llvm_unreachable("Unsupported imm check"); 286*5ffd83dbSDimitry Andric } 287*5ffd83dbSDimitry Andric 288*5ffd83dbSDimitry Andric /// Returns the enum value for the flag type 289*5ffd83dbSDimitry Andric uint64_t getEnumValueForFlag(StringRef C) const { 290*5ffd83dbSDimitry Andric auto Res = FlagTypes.find(C); 291*5ffd83dbSDimitry Andric if (Res != FlagTypes.end()) 292*5ffd83dbSDimitry Andric return Res->getValue(); 293*5ffd83dbSDimitry Andric llvm_unreachable("Unsupported flag"); 294*5ffd83dbSDimitry Andric } 295*5ffd83dbSDimitry Andric 296*5ffd83dbSDimitry Andric // Returns the SVETypeFlags for a given value and mask. 297*5ffd83dbSDimitry Andric uint64_t encodeFlag(uint64_t V, StringRef MaskName) const { 298*5ffd83dbSDimitry Andric auto It = FlagTypes.find(MaskName); 299*5ffd83dbSDimitry Andric if (It != FlagTypes.end()) { 300*5ffd83dbSDimitry Andric uint64_t Mask = It->getValue(); 301*5ffd83dbSDimitry Andric unsigned Shift = llvm::countTrailingZeros(Mask); 302*5ffd83dbSDimitry Andric return (V << Shift) & Mask; 303*5ffd83dbSDimitry Andric } 304*5ffd83dbSDimitry Andric llvm_unreachable("Unsupported flag"); 305*5ffd83dbSDimitry Andric } 306*5ffd83dbSDimitry Andric 307*5ffd83dbSDimitry Andric // Returns the SVETypeFlags for the given element type. 308*5ffd83dbSDimitry Andric uint64_t encodeEltType(StringRef EltName) { 309*5ffd83dbSDimitry Andric auto It = EltTypes.find(EltName); 310*5ffd83dbSDimitry Andric if (It != EltTypes.end()) 311*5ffd83dbSDimitry Andric return encodeFlag(It->getValue(), "EltTypeMask"); 312*5ffd83dbSDimitry Andric llvm_unreachable("Unsupported EltType"); 313*5ffd83dbSDimitry Andric } 314*5ffd83dbSDimitry Andric 315*5ffd83dbSDimitry Andric // Returns the SVETypeFlags for the given memory element type. 316*5ffd83dbSDimitry Andric uint64_t encodeMemoryElementType(uint64_t MT) { 317*5ffd83dbSDimitry Andric return encodeFlag(MT, "MemEltTypeMask"); 318*5ffd83dbSDimitry Andric } 319*5ffd83dbSDimitry Andric 320*5ffd83dbSDimitry Andric // Returns the SVETypeFlags for the given merge type. 321*5ffd83dbSDimitry Andric uint64_t encodeMergeType(uint64_t MT) { 322*5ffd83dbSDimitry Andric return encodeFlag(MT, "MergeTypeMask"); 323*5ffd83dbSDimitry Andric } 324*5ffd83dbSDimitry Andric 325*5ffd83dbSDimitry Andric // Returns the SVETypeFlags for the given splat operand. 326*5ffd83dbSDimitry Andric unsigned encodeSplatOperand(unsigned SplatIdx) { 327*5ffd83dbSDimitry Andric assert(SplatIdx < 7 && "SplatIdx out of encodable range"); 328*5ffd83dbSDimitry Andric return encodeFlag(SplatIdx + 1, "SplatOperandMask"); 329*5ffd83dbSDimitry Andric } 330*5ffd83dbSDimitry Andric 331*5ffd83dbSDimitry Andric // Returns the SVETypeFlags value for the given SVEType. 332*5ffd83dbSDimitry Andric uint64_t encodeTypeFlags(const SVEType &T); 333*5ffd83dbSDimitry Andric 334*5ffd83dbSDimitry Andric /// Emit arm_sve.h. 335*5ffd83dbSDimitry Andric void createHeader(raw_ostream &o); 336*5ffd83dbSDimitry Andric 337*5ffd83dbSDimitry Andric /// Emit all the __builtin prototypes and code needed by Sema. 338*5ffd83dbSDimitry Andric void createBuiltins(raw_ostream &o); 339*5ffd83dbSDimitry Andric 340*5ffd83dbSDimitry Andric /// Emit all the information needed to map builtin -> LLVM IR intrinsic. 341*5ffd83dbSDimitry Andric void createCodeGenMap(raw_ostream &o); 342*5ffd83dbSDimitry Andric 343*5ffd83dbSDimitry Andric /// Emit all the range checks for the immediates. 344*5ffd83dbSDimitry Andric void createRangeChecks(raw_ostream &o); 345*5ffd83dbSDimitry Andric 346*5ffd83dbSDimitry Andric /// Create the SVETypeFlags used in CGBuiltins 347*5ffd83dbSDimitry Andric void createTypeFlags(raw_ostream &o); 348*5ffd83dbSDimitry Andric 349*5ffd83dbSDimitry Andric /// Create intrinsic and add it to \p Out 350*5ffd83dbSDimitry Andric void createIntrinsic(Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out); 351*5ffd83dbSDimitry Andric }; 352*5ffd83dbSDimitry Andric 353*5ffd83dbSDimitry Andric } // end anonymous namespace 354*5ffd83dbSDimitry Andric 355*5ffd83dbSDimitry Andric 356*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 357*5ffd83dbSDimitry Andric // Type implementation 358*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 359*5ffd83dbSDimitry Andric 360*5ffd83dbSDimitry Andric std::string SVEType::builtin_str() const { 361*5ffd83dbSDimitry Andric std::string S; 362*5ffd83dbSDimitry Andric if (isVoid()) 363*5ffd83dbSDimitry Andric return "v"; 364*5ffd83dbSDimitry Andric 365*5ffd83dbSDimitry Andric if (isVoidPointer()) 366*5ffd83dbSDimitry Andric S += "v"; 367*5ffd83dbSDimitry Andric else if (!isFloatingPoint()) 368*5ffd83dbSDimitry Andric switch (ElementBitwidth) { 369*5ffd83dbSDimitry Andric case 1: S += "b"; break; 370*5ffd83dbSDimitry Andric case 8: S += "c"; break; 371*5ffd83dbSDimitry Andric case 16: S += "s"; break; 372*5ffd83dbSDimitry Andric case 32: S += "i"; break; 373*5ffd83dbSDimitry Andric case 64: S += "Wi"; break; 374*5ffd83dbSDimitry Andric case 128: S += "LLLi"; break; 375*5ffd83dbSDimitry Andric default: llvm_unreachable("Unhandled case!"); 376*5ffd83dbSDimitry Andric } 377*5ffd83dbSDimitry Andric else if (isFloat()) 378*5ffd83dbSDimitry Andric switch (ElementBitwidth) { 379*5ffd83dbSDimitry Andric case 16: S += "h"; break; 380*5ffd83dbSDimitry Andric case 32: S += "f"; break; 381*5ffd83dbSDimitry Andric case 64: S += "d"; break; 382*5ffd83dbSDimitry Andric default: llvm_unreachable("Unhandled case!"); 383*5ffd83dbSDimitry Andric } 384*5ffd83dbSDimitry Andric else if (isBFloat()) { 385*5ffd83dbSDimitry Andric assert(ElementBitwidth == 16 && "Not a valid BFloat."); 386*5ffd83dbSDimitry Andric S += "y"; 387*5ffd83dbSDimitry Andric } 388*5ffd83dbSDimitry Andric 389*5ffd83dbSDimitry Andric if (!isFloatingPoint()) { 390*5ffd83dbSDimitry Andric if ((isChar() || isPointer()) && !isVoidPointer()) { 391*5ffd83dbSDimitry Andric // Make chars and typed pointers explicitly signed. 392*5ffd83dbSDimitry Andric if (Signed) 393*5ffd83dbSDimitry Andric S = "S" + S; 394*5ffd83dbSDimitry Andric else if (!Signed) 395*5ffd83dbSDimitry Andric S = "U" + S; 396*5ffd83dbSDimitry Andric } else if (!isVoidPointer() && !Signed) { 397*5ffd83dbSDimitry Andric S = "U" + S; 398*5ffd83dbSDimitry Andric } 399*5ffd83dbSDimitry Andric } 400*5ffd83dbSDimitry Andric 401*5ffd83dbSDimitry Andric // Constant indices are "int", but have the "constant expression" modifier. 402*5ffd83dbSDimitry Andric if (isImmediate()) { 403*5ffd83dbSDimitry Andric assert(!isFloat() && "fp immediates are not supported"); 404*5ffd83dbSDimitry Andric S = "I" + S; 405*5ffd83dbSDimitry Andric } 406*5ffd83dbSDimitry Andric 407*5ffd83dbSDimitry Andric if (isScalar()) { 408*5ffd83dbSDimitry Andric if (Constant) S += "C"; 409*5ffd83dbSDimitry Andric if (Pointer) S += "*"; 410*5ffd83dbSDimitry Andric return S; 411*5ffd83dbSDimitry Andric } 412*5ffd83dbSDimitry Andric 413*5ffd83dbSDimitry Andric assert(isScalableVector() && "Unsupported type"); 414*5ffd83dbSDimitry Andric return "q" + utostr(getNumElements() * NumVectors) + S; 415*5ffd83dbSDimitry Andric } 416*5ffd83dbSDimitry Andric 417*5ffd83dbSDimitry Andric std::string SVEType::str() const { 418*5ffd83dbSDimitry Andric if (isPredicatePattern()) 419*5ffd83dbSDimitry Andric return "sv_pattern"; 420*5ffd83dbSDimitry Andric 421*5ffd83dbSDimitry Andric if (isPrefetchOp()) 422*5ffd83dbSDimitry Andric return "sv_prfop"; 423*5ffd83dbSDimitry Andric 424*5ffd83dbSDimitry Andric std::string S; 425*5ffd83dbSDimitry Andric if (Void) 426*5ffd83dbSDimitry Andric S += "void"; 427*5ffd83dbSDimitry Andric else { 428*5ffd83dbSDimitry Andric if (isScalableVector()) 429*5ffd83dbSDimitry Andric S += "sv"; 430*5ffd83dbSDimitry Andric if (!Signed && !isFloatingPoint()) 431*5ffd83dbSDimitry Andric S += "u"; 432*5ffd83dbSDimitry Andric 433*5ffd83dbSDimitry Andric if (Float) 434*5ffd83dbSDimitry Andric S += "float"; 435*5ffd83dbSDimitry Andric else if (isScalarPredicate() || isPredicateVector()) 436*5ffd83dbSDimitry Andric S += "bool"; 437*5ffd83dbSDimitry Andric else if (isBFloat()) 438*5ffd83dbSDimitry Andric S += "bfloat"; 439*5ffd83dbSDimitry Andric else 440*5ffd83dbSDimitry Andric S += "int"; 441*5ffd83dbSDimitry Andric 442*5ffd83dbSDimitry Andric if (!isScalarPredicate() && !isPredicateVector()) 443*5ffd83dbSDimitry Andric S += utostr(ElementBitwidth); 444*5ffd83dbSDimitry Andric if (!isScalableVector() && isVector()) 445*5ffd83dbSDimitry Andric S += "x" + utostr(getNumElements()); 446*5ffd83dbSDimitry Andric if (NumVectors > 1) 447*5ffd83dbSDimitry Andric S += "x" + utostr(NumVectors); 448*5ffd83dbSDimitry Andric if (!isScalarPredicate()) 449*5ffd83dbSDimitry Andric S += "_t"; 450*5ffd83dbSDimitry Andric } 451*5ffd83dbSDimitry Andric 452*5ffd83dbSDimitry Andric if (Constant) 453*5ffd83dbSDimitry Andric S += " const"; 454*5ffd83dbSDimitry Andric if (Pointer) 455*5ffd83dbSDimitry Andric S += " *"; 456*5ffd83dbSDimitry Andric 457*5ffd83dbSDimitry Andric return S; 458*5ffd83dbSDimitry Andric } 459*5ffd83dbSDimitry Andric void SVEType::applyTypespec() { 460*5ffd83dbSDimitry Andric for (char I : TS) { 461*5ffd83dbSDimitry Andric switch (I) { 462*5ffd83dbSDimitry Andric case 'P': 463*5ffd83dbSDimitry Andric Predicate = true; 464*5ffd83dbSDimitry Andric break; 465*5ffd83dbSDimitry Andric case 'U': 466*5ffd83dbSDimitry Andric Signed = false; 467*5ffd83dbSDimitry Andric break; 468*5ffd83dbSDimitry Andric case 'c': 469*5ffd83dbSDimitry Andric ElementBitwidth = 8; 470*5ffd83dbSDimitry Andric break; 471*5ffd83dbSDimitry Andric case 's': 472*5ffd83dbSDimitry Andric ElementBitwidth = 16; 473*5ffd83dbSDimitry Andric break; 474*5ffd83dbSDimitry Andric case 'i': 475*5ffd83dbSDimitry Andric ElementBitwidth = 32; 476*5ffd83dbSDimitry Andric break; 477*5ffd83dbSDimitry Andric case 'l': 478*5ffd83dbSDimitry Andric ElementBitwidth = 64; 479*5ffd83dbSDimitry Andric break; 480*5ffd83dbSDimitry Andric case 'h': 481*5ffd83dbSDimitry Andric Float = true; 482*5ffd83dbSDimitry Andric ElementBitwidth = 16; 483*5ffd83dbSDimitry Andric break; 484*5ffd83dbSDimitry Andric case 'f': 485*5ffd83dbSDimitry Andric Float = true; 486*5ffd83dbSDimitry Andric ElementBitwidth = 32; 487*5ffd83dbSDimitry Andric break; 488*5ffd83dbSDimitry Andric case 'd': 489*5ffd83dbSDimitry Andric Float = true; 490*5ffd83dbSDimitry Andric ElementBitwidth = 64; 491*5ffd83dbSDimitry Andric break; 492*5ffd83dbSDimitry Andric case 'b': 493*5ffd83dbSDimitry Andric BFloat = true; 494*5ffd83dbSDimitry Andric Float = false; 495*5ffd83dbSDimitry Andric ElementBitwidth = 16; 496*5ffd83dbSDimitry Andric break; 497*5ffd83dbSDimitry Andric default: 498*5ffd83dbSDimitry Andric llvm_unreachable("Unhandled type code!"); 499*5ffd83dbSDimitry Andric } 500*5ffd83dbSDimitry Andric } 501*5ffd83dbSDimitry Andric assert(ElementBitwidth != ~0U && "Bad element bitwidth!"); 502*5ffd83dbSDimitry Andric } 503*5ffd83dbSDimitry Andric 504*5ffd83dbSDimitry Andric void SVEType::applyModifier(char Mod) { 505*5ffd83dbSDimitry Andric switch (Mod) { 506*5ffd83dbSDimitry Andric case '2': 507*5ffd83dbSDimitry Andric NumVectors = 2; 508*5ffd83dbSDimitry Andric break; 509*5ffd83dbSDimitry Andric case '3': 510*5ffd83dbSDimitry Andric NumVectors = 3; 511*5ffd83dbSDimitry Andric break; 512*5ffd83dbSDimitry Andric case '4': 513*5ffd83dbSDimitry Andric NumVectors = 4; 514*5ffd83dbSDimitry Andric break; 515*5ffd83dbSDimitry Andric case 'v': 516*5ffd83dbSDimitry Andric Void = true; 517*5ffd83dbSDimitry Andric break; 518*5ffd83dbSDimitry Andric case 'd': 519*5ffd83dbSDimitry Andric DefaultType = true; 520*5ffd83dbSDimitry Andric break; 521*5ffd83dbSDimitry Andric case 'c': 522*5ffd83dbSDimitry Andric Constant = true; 523*5ffd83dbSDimitry Andric LLVM_FALLTHROUGH; 524*5ffd83dbSDimitry Andric case 'p': 525*5ffd83dbSDimitry Andric Pointer = true; 526*5ffd83dbSDimitry Andric Bitwidth = ElementBitwidth; 527*5ffd83dbSDimitry Andric NumVectors = 0; 528*5ffd83dbSDimitry Andric break; 529*5ffd83dbSDimitry Andric case 'e': 530*5ffd83dbSDimitry Andric Signed = false; 531*5ffd83dbSDimitry Andric ElementBitwidth /= 2; 532*5ffd83dbSDimitry Andric break; 533*5ffd83dbSDimitry Andric case 'h': 534*5ffd83dbSDimitry Andric ElementBitwidth /= 2; 535*5ffd83dbSDimitry Andric break; 536*5ffd83dbSDimitry Andric case 'q': 537*5ffd83dbSDimitry Andric ElementBitwidth /= 4; 538*5ffd83dbSDimitry Andric break; 539*5ffd83dbSDimitry Andric case 'b': 540*5ffd83dbSDimitry Andric Signed = false; 541*5ffd83dbSDimitry Andric Float = false; 542*5ffd83dbSDimitry Andric BFloat = false; 543*5ffd83dbSDimitry Andric ElementBitwidth /= 4; 544*5ffd83dbSDimitry Andric break; 545*5ffd83dbSDimitry Andric case 'o': 546*5ffd83dbSDimitry Andric ElementBitwidth *= 4; 547*5ffd83dbSDimitry Andric break; 548*5ffd83dbSDimitry Andric case 'P': 549*5ffd83dbSDimitry Andric Signed = true; 550*5ffd83dbSDimitry Andric Float = false; 551*5ffd83dbSDimitry Andric BFloat = false; 552*5ffd83dbSDimitry Andric Predicate = true; 553*5ffd83dbSDimitry Andric Bitwidth = 16; 554*5ffd83dbSDimitry Andric ElementBitwidth = 1; 555*5ffd83dbSDimitry Andric break; 556*5ffd83dbSDimitry Andric case 's': 557*5ffd83dbSDimitry Andric case 'a': 558*5ffd83dbSDimitry Andric Bitwidth = ElementBitwidth; 559*5ffd83dbSDimitry Andric NumVectors = 0; 560*5ffd83dbSDimitry Andric break; 561*5ffd83dbSDimitry Andric case 'R': 562*5ffd83dbSDimitry Andric ElementBitwidth /= 2; 563*5ffd83dbSDimitry Andric NumVectors = 0; 564*5ffd83dbSDimitry Andric break; 565*5ffd83dbSDimitry Andric case 'r': 566*5ffd83dbSDimitry Andric ElementBitwidth /= 4; 567*5ffd83dbSDimitry Andric NumVectors = 0; 568*5ffd83dbSDimitry Andric break; 569*5ffd83dbSDimitry Andric case '@': 570*5ffd83dbSDimitry Andric Signed = false; 571*5ffd83dbSDimitry Andric Float = false; 572*5ffd83dbSDimitry Andric BFloat = false; 573*5ffd83dbSDimitry Andric ElementBitwidth /= 4; 574*5ffd83dbSDimitry Andric NumVectors = 0; 575*5ffd83dbSDimitry Andric break; 576*5ffd83dbSDimitry Andric case 'K': 577*5ffd83dbSDimitry Andric Signed = true; 578*5ffd83dbSDimitry Andric Float = false; 579*5ffd83dbSDimitry Andric BFloat = false; 580*5ffd83dbSDimitry Andric Bitwidth = ElementBitwidth; 581*5ffd83dbSDimitry Andric NumVectors = 0; 582*5ffd83dbSDimitry Andric break; 583*5ffd83dbSDimitry Andric case 'L': 584*5ffd83dbSDimitry Andric Signed = false; 585*5ffd83dbSDimitry Andric Float = false; 586*5ffd83dbSDimitry Andric BFloat = false; 587*5ffd83dbSDimitry Andric Bitwidth = ElementBitwidth; 588*5ffd83dbSDimitry Andric NumVectors = 0; 589*5ffd83dbSDimitry Andric break; 590*5ffd83dbSDimitry Andric case 'u': 591*5ffd83dbSDimitry Andric Predicate = false; 592*5ffd83dbSDimitry Andric Signed = false; 593*5ffd83dbSDimitry Andric Float = false; 594*5ffd83dbSDimitry Andric BFloat = false; 595*5ffd83dbSDimitry Andric break; 596*5ffd83dbSDimitry Andric case 'x': 597*5ffd83dbSDimitry Andric Predicate = false; 598*5ffd83dbSDimitry Andric Signed = true; 599*5ffd83dbSDimitry Andric Float = false; 600*5ffd83dbSDimitry Andric BFloat = false; 601*5ffd83dbSDimitry Andric break; 602*5ffd83dbSDimitry Andric case 'i': 603*5ffd83dbSDimitry Andric Predicate = false; 604*5ffd83dbSDimitry Andric Float = false; 605*5ffd83dbSDimitry Andric BFloat = false; 606*5ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 64; 607*5ffd83dbSDimitry Andric NumVectors = 0; 608*5ffd83dbSDimitry Andric Signed = false; 609*5ffd83dbSDimitry Andric Immediate = true; 610*5ffd83dbSDimitry Andric break; 611*5ffd83dbSDimitry Andric case 'I': 612*5ffd83dbSDimitry Andric Predicate = false; 613*5ffd83dbSDimitry Andric Float = false; 614*5ffd83dbSDimitry Andric BFloat = false; 615*5ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 32; 616*5ffd83dbSDimitry Andric NumVectors = 0; 617*5ffd83dbSDimitry Andric Signed = true; 618*5ffd83dbSDimitry Andric Immediate = true; 619*5ffd83dbSDimitry Andric PredicatePattern = true; 620*5ffd83dbSDimitry Andric break; 621*5ffd83dbSDimitry Andric case 'J': 622*5ffd83dbSDimitry Andric Predicate = false; 623*5ffd83dbSDimitry Andric Float = false; 624*5ffd83dbSDimitry Andric BFloat = false; 625*5ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 32; 626*5ffd83dbSDimitry Andric NumVectors = 0; 627*5ffd83dbSDimitry Andric Signed = true; 628*5ffd83dbSDimitry Andric Immediate = true; 629*5ffd83dbSDimitry Andric PrefetchOp = true; 630*5ffd83dbSDimitry Andric break; 631*5ffd83dbSDimitry Andric case 'k': 632*5ffd83dbSDimitry Andric Predicate = false; 633*5ffd83dbSDimitry Andric Signed = true; 634*5ffd83dbSDimitry Andric Float = false; 635*5ffd83dbSDimitry Andric BFloat = false; 636*5ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 32; 637*5ffd83dbSDimitry Andric NumVectors = 0; 638*5ffd83dbSDimitry Andric break; 639*5ffd83dbSDimitry Andric case 'l': 640*5ffd83dbSDimitry Andric Predicate = false; 641*5ffd83dbSDimitry Andric Signed = true; 642*5ffd83dbSDimitry Andric Float = false; 643*5ffd83dbSDimitry Andric BFloat = false; 644*5ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 64; 645*5ffd83dbSDimitry Andric NumVectors = 0; 646*5ffd83dbSDimitry Andric break; 647*5ffd83dbSDimitry Andric case 'm': 648*5ffd83dbSDimitry Andric Predicate = false; 649*5ffd83dbSDimitry Andric Signed = false; 650*5ffd83dbSDimitry Andric Float = false; 651*5ffd83dbSDimitry Andric BFloat = false; 652*5ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 32; 653*5ffd83dbSDimitry Andric NumVectors = 0; 654*5ffd83dbSDimitry Andric break; 655*5ffd83dbSDimitry Andric case 'n': 656*5ffd83dbSDimitry Andric Predicate = false; 657*5ffd83dbSDimitry Andric Signed = false; 658*5ffd83dbSDimitry Andric Float = false; 659*5ffd83dbSDimitry Andric BFloat = false; 660*5ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 64; 661*5ffd83dbSDimitry Andric NumVectors = 0; 662*5ffd83dbSDimitry Andric break; 663*5ffd83dbSDimitry Andric case 'w': 664*5ffd83dbSDimitry Andric ElementBitwidth = 64; 665*5ffd83dbSDimitry Andric break; 666*5ffd83dbSDimitry Andric case 'j': 667*5ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 64; 668*5ffd83dbSDimitry Andric NumVectors = 0; 669*5ffd83dbSDimitry Andric break; 670*5ffd83dbSDimitry Andric case 'f': 671*5ffd83dbSDimitry Andric Signed = false; 672*5ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 64; 673*5ffd83dbSDimitry Andric NumVectors = 0; 674*5ffd83dbSDimitry Andric break; 675*5ffd83dbSDimitry Andric case 'g': 676*5ffd83dbSDimitry Andric Signed = false; 677*5ffd83dbSDimitry Andric Float = false; 678*5ffd83dbSDimitry Andric BFloat = false; 679*5ffd83dbSDimitry Andric ElementBitwidth = 64; 680*5ffd83dbSDimitry Andric break; 681*5ffd83dbSDimitry Andric case 't': 682*5ffd83dbSDimitry Andric Signed = true; 683*5ffd83dbSDimitry Andric Float = false; 684*5ffd83dbSDimitry Andric BFloat = false; 685*5ffd83dbSDimitry Andric ElementBitwidth = 32; 686*5ffd83dbSDimitry Andric break; 687*5ffd83dbSDimitry Andric case 'z': 688*5ffd83dbSDimitry Andric Signed = false; 689*5ffd83dbSDimitry Andric Float = false; 690*5ffd83dbSDimitry Andric BFloat = false; 691*5ffd83dbSDimitry Andric ElementBitwidth = 32; 692*5ffd83dbSDimitry Andric break; 693*5ffd83dbSDimitry Andric case 'O': 694*5ffd83dbSDimitry Andric Predicate = false; 695*5ffd83dbSDimitry Andric Float = true; 696*5ffd83dbSDimitry Andric ElementBitwidth = 16; 697*5ffd83dbSDimitry Andric break; 698*5ffd83dbSDimitry Andric case 'M': 699*5ffd83dbSDimitry Andric Predicate = false; 700*5ffd83dbSDimitry Andric Float = true; 701*5ffd83dbSDimitry Andric BFloat = false; 702*5ffd83dbSDimitry Andric ElementBitwidth = 32; 703*5ffd83dbSDimitry Andric break; 704*5ffd83dbSDimitry Andric case 'N': 705*5ffd83dbSDimitry Andric Predicate = false; 706*5ffd83dbSDimitry Andric Float = true; 707*5ffd83dbSDimitry Andric ElementBitwidth = 64; 708*5ffd83dbSDimitry Andric break; 709*5ffd83dbSDimitry Andric case 'Q': 710*5ffd83dbSDimitry Andric Constant = true; 711*5ffd83dbSDimitry Andric Pointer = true; 712*5ffd83dbSDimitry Andric Void = true; 713*5ffd83dbSDimitry Andric NumVectors = 0; 714*5ffd83dbSDimitry Andric break; 715*5ffd83dbSDimitry Andric case 'S': 716*5ffd83dbSDimitry Andric Constant = true; 717*5ffd83dbSDimitry Andric Pointer = true; 718*5ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 8; 719*5ffd83dbSDimitry Andric NumVectors = 0; 720*5ffd83dbSDimitry Andric Signed = true; 721*5ffd83dbSDimitry Andric break; 722*5ffd83dbSDimitry Andric case 'W': 723*5ffd83dbSDimitry Andric Constant = true; 724*5ffd83dbSDimitry Andric Pointer = true; 725*5ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 8; 726*5ffd83dbSDimitry Andric NumVectors = 0; 727*5ffd83dbSDimitry Andric Signed = false; 728*5ffd83dbSDimitry Andric break; 729*5ffd83dbSDimitry Andric case 'T': 730*5ffd83dbSDimitry Andric Constant = true; 731*5ffd83dbSDimitry Andric Pointer = true; 732*5ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 16; 733*5ffd83dbSDimitry Andric NumVectors = 0; 734*5ffd83dbSDimitry Andric Signed = true; 735*5ffd83dbSDimitry Andric break; 736*5ffd83dbSDimitry Andric case 'X': 737*5ffd83dbSDimitry Andric Constant = true; 738*5ffd83dbSDimitry Andric Pointer = true; 739*5ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 16; 740*5ffd83dbSDimitry Andric NumVectors = 0; 741*5ffd83dbSDimitry Andric Signed = false; 742*5ffd83dbSDimitry Andric break; 743*5ffd83dbSDimitry Andric case 'Y': 744*5ffd83dbSDimitry Andric Constant = true; 745*5ffd83dbSDimitry Andric Pointer = true; 746*5ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 32; 747*5ffd83dbSDimitry Andric NumVectors = 0; 748*5ffd83dbSDimitry Andric Signed = false; 749*5ffd83dbSDimitry Andric break; 750*5ffd83dbSDimitry Andric case 'U': 751*5ffd83dbSDimitry Andric Constant = true; 752*5ffd83dbSDimitry Andric Pointer = true; 753*5ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 32; 754*5ffd83dbSDimitry Andric NumVectors = 0; 755*5ffd83dbSDimitry Andric Signed = true; 756*5ffd83dbSDimitry Andric break; 757*5ffd83dbSDimitry Andric case 'A': 758*5ffd83dbSDimitry Andric Pointer = true; 759*5ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 8; 760*5ffd83dbSDimitry Andric NumVectors = 0; 761*5ffd83dbSDimitry Andric Signed = true; 762*5ffd83dbSDimitry Andric break; 763*5ffd83dbSDimitry Andric case 'B': 764*5ffd83dbSDimitry Andric Pointer = true; 765*5ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 16; 766*5ffd83dbSDimitry Andric NumVectors = 0; 767*5ffd83dbSDimitry Andric Signed = true; 768*5ffd83dbSDimitry Andric break; 769*5ffd83dbSDimitry Andric case 'C': 770*5ffd83dbSDimitry Andric Pointer = true; 771*5ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 32; 772*5ffd83dbSDimitry Andric NumVectors = 0; 773*5ffd83dbSDimitry Andric Signed = true; 774*5ffd83dbSDimitry Andric break; 775*5ffd83dbSDimitry Andric case 'D': 776*5ffd83dbSDimitry Andric Pointer = true; 777*5ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 64; 778*5ffd83dbSDimitry Andric NumVectors = 0; 779*5ffd83dbSDimitry Andric Signed = true; 780*5ffd83dbSDimitry Andric break; 781*5ffd83dbSDimitry Andric case 'E': 782*5ffd83dbSDimitry Andric Pointer = true; 783*5ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 8; 784*5ffd83dbSDimitry Andric NumVectors = 0; 785*5ffd83dbSDimitry Andric Signed = false; 786*5ffd83dbSDimitry Andric break; 787*5ffd83dbSDimitry Andric case 'F': 788*5ffd83dbSDimitry Andric Pointer = true; 789*5ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 16; 790*5ffd83dbSDimitry Andric NumVectors = 0; 791*5ffd83dbSDimitry Andric Signed = false; 792*5ffd83dbSDimitry Andric break; 793*5ffd83dbSDimitry Andric case 'G': 794*5ffd83dbSDimitry Andric Pointer = true; 795*5ffd83dbSDimitry Andric ElementBitwidth = Bitwidth = 32; 796*5ffd83dbSDimitry Andric NumVectors = 0; 797*5ffd83dbSDimitry Andric Signed = false; 798*5ffd83dbSDimitry Andric break; 799*5ffd83dbSDimitry Andric default: 800*5ffd83dbSDimitry Andric llvm_unreachable("Unhandled character!"); 801*5ffd83dbSDimitry Andric } 802*5ffd83dbSDimitry Andric } 803*5ffd83dbSDimitry Andric 804*5ffd83dbSDimitry Andric 805*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 806*5ffd83dbSDimitry Andric // Intrinsic implementation 807*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 808*5ffd83dbSDimitry Andric 809*5ffd83dbSDimitry Andric Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy, 810*5ffd83dbSDimitry Andric StringRef MergeSuffix, uint64_t MemoryElementTy, 811*5ffd83dbSDimitry Andric StringRef LLVMName, uint64_t Flags, 812*5ffd83dbSDimitry Andric ArrayRef<ImmCheck> Checks, TypeSpec BT, ClassKind Class, 813*5ffd83dbSDimitry Andric SVEEmitter &Emitter, StringRef Guard) 814*5ffd83dbSDimitry Andric : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()), 815*5ffd83dbSDimitry Andric BaseTypeSpec(BT), Class(Class), Guard(Guard.str()), 816*5ffd83dbSDimitry Andric MergeSuffix(MergeSuffix.str()), BaseType(BT, 'd'), Flags(Flags), 817*5ffd83dbSDimitry Andric ImmChecks(Checks.begin(), Checks.end()) { 818*5ffd83dbSDimitry Andric // Types[0] is the return value. 819*5ffd83dbSDimitry Andric for (unsigned I = 0; I < Proto.size(); ++I) { 820*5ffd83dbSDimitry Andric SVEType T(BaseTypeSpec, Proto[I]); 821*5ffd83dbSDimitry Andric Types.push_back(T); 822*5ffd83dbSDimitry Andric 823*5ffd83dbSDimitry Andric // Add range checks for immediates 824*5ffd83dbSDimitry Andric if (I > 0) { 825*5ffd83dbSDimitry Andric if (T.isPredicatePattern()) 826*5ffd83dbSDimitry Andric ImmChecks.emplace_back( 827*5ffd83dbSDimitry Andric I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_31")); 828*5ffd83dbSDimitry Andric else if (T.isPrefetchOp()) 829*5ffd83dbSDimitry Andric ImmChecks.emplace_back( 830*5ffd83dbSDimitry Andric I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_13")); 831*5ffd83dbSDimitry Andric } 832*5ffd83dbSDimitry Andric } 833*5ffd83dbSDimitry Andric 834*5ffd83dbSDimitry Andric // Set flags based on properties 835*5ffd83dbSDimitry Andric this->Flags |= Emitter.encodeTypeFlags(BaseType); 836*5ffd83dbSDimitry Andric this->Flags |= Emitter.encodeMemoryElementType(MemoryElementTy); 837*5ffd83dbSDimitry Andric this->Flags |= Emitter.encodeMergeType(MergeTy); 838*5ffd83dbSDimitry Andric if (hasSplat()) 839*5ffd83dbSDimitry Andric this->Flags |= Emitter.encodeSplatOperand(getSplatIdx()); 840*5ffd83dbSDimitry Andric } 841*5ffd83dbSDimitry Andric 842*5ffd83dbSDimitry Andric std::string Intrinsic::getBuiltinTypeStr() { 843*5ffd83dbSDimitry Andric std::string S = getReturnType().builtin_str(); 844*5ffd83dbSDimitry Andric for (unsigned I = 0; I < getNumParams(); ++I) 845*5ffd83dbSDimitry Andric S += getParamType(I).builtin_str(); 846*5ffd83dbSDimitry Andric 847*5ffd83dbSDimitry Andric return S; 848*5ffd83dbSDimitry Andric } 849*5ffd83dbSDimitry Andric 850*5ffd83dbSDimitry Andric std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS, 851*5ffd83dbSDimitry Andric std::string Proto) const { 852*5ffd83dbSDimitry Andric std::string Ret = Name; 853*5ffd83dbSDimitry Andric while (Ret.find('{') != std::string::npos) { 854*5ffd83dbSDimitry Andric size_t Pos = Ret.find('{'); 855*5ffd83dbSDimitry Andric size_t End = Ret.find('}'); 856*5ffd83dbSDimitry Andric unsigned NumChars = End - Pos + 1; 857*5ffd83dbSDimitry Andric assert(NumChars == 3 && "Unexpected template argument"); 858*5ffd83dbSDimitry Andric 859*5ffd83dbSDimitry Andric SVEType T; 860*5ffd83dbSDimitry Andric char C = Ret[Pos+1]; 861*5ffd83dbSDimitry Andric switch(C) { 862*5ffd83dbSDimitry Andric default: 863*5ffd83dbSDimitry Andric llvm_unreachable("Unknown predication specifier"); 864*5ffd83dbSDimitry Andric case 'd': 865*5ffd83dbSDimitry Andric T = SVEType(TS, 'd'); 866*5ffd83dbSDimitry Andric break; 867*5ffd83dbSDimitry Andric case '0': 868*5ffd83dbSDimitry Andric case '1': 869*5ffd83dbSDimitry Andric case '2': 870*5ffd83dbSDimitry Andric case '3': 871*5ffd83dbSDimitry Andric T = SVEType(TS, Proto[C - '0']); 872*5ffd83dbSDimitry Andric break; 873*5ffd83dbSDimitry Andric } 874*5ffd83dbSDimitry Andric 875*5ffd83dbSDimitry Andric // Replace templated arg with the right suffix (e.g. u32) 876*5ffd83dbSDimitry Andric std::string TypeCode; 877*5ffd83dbSDimitry Andric if (T.isInteger()) 878*5ffd83dbSDimitry Andric TypeCode = T.isSigned() ? 's' : 'u'; 879*5ffd83dbSDimitry Andric else if (T.isPredicateVector()) 880*5ffd83dbSDimitry Andric TypeCode = 'b'; 881*5ffd83dbSDimitry Andric else if (T.isBFloat()) 882*5ffd83dbSDimitry Andric TypeCode = "bf"; 883*5ffd83dbSDimitry Andric else 884*5ffd83dbSDimitry Andric TypeCode = 'f'; 885*5ffd83dbSDimitry Andric Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits())); 886*5ffd83dbSDimitry Andric } 887*5ffd83dbSDimitry Andric 888*5ffd83dbSDimitry Andric return Ret; 889*5ffd83dbSDimitry Andric } 890*5ffd83dbSDimitry Andric 891*5ffd83dbSDimitry Andric std::string Intrinsic::mangleName(ClassKind LocalCK) const { 892*5ffd83dbSDimitry Andric std::string S = getName(); 893*5ffd83dbSDimitry Andric 894*5ffd83dbSDimitry Andric if (LocalCK == ClassG) { 895*5ffd83dbSDimitry Andric // Remove the square brackets and everything in between. 896*5ffd83dbSDimitry Andric while (S.find("[") != std::string::npos) { 897*5ffd83dbSDimitry Andric auto Start = S.find("["); 898*5ffd83dbSDimitry Andric auto End = S.find(']'); 899*5ffd83dbSDimitry Andric S.erase(Start, (End-Start)+1); 900*5ffd83dbSDimitry Andric } 901*5ffd83dbSDimitry Andric } else { 902*5ffd83dbSDimitry Andric // Remove the square brackets. 903*5ffd83dbSDimitry Andric while (S.find("[") != std::string::npos) { 904*5ffd83dbSDimitry Andric auto BrPos = S.find('['); 905*5ffd83dbSDimitry Andric if (BrPos != std::string::npos) 906*5ffd83dbSDimitry Andric S.erase(BrPos, 1); 907*5ffd83dbSDimitry Andric BrPos = S.find(']'); 908*5ffd83dbSDimitry Andric if (BrPos != std::string::npos) 909*5ffd83dbSDimitry Andric S.erase(BrPos, 1); 910*5ffd83dbSDimitry Andric } 911*5ffd83dbSDimitry Andric } 912*5ffd83dbSDimitry Andric 913*5ffd83dbSDimitry Andric // Replace all {d} like expressions with e.g. 'u32' 914*5ffd83dbSDimitry Andric return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) + 915*5ffd83dbSDimitry Andric getMergeSuffix(); 916*5ffd83dbSDimitry Andric } 917*5ffd83dbSDimitry Andric 918*5ffd83dbSDimitry Andric void Intrinsic::emitIntrinsic(raw_ostream &OS) const { 919*5ffd83dbSDimitry Andric // Use the preprocessor to 920*5ffd83dbSDimitry Andric if (getClassKind() != ClassG || getProto().size() <= 1) { 921*5ffd83dbSDimitry Andric OS << "#define " << mangleName(getClassKind()) 922*5ffd83dbSDimitry Andric << "(...) __builtin_sve_" << mangleName(ClassS) 923*5ffd83dbSDimitry Andric << "(__VA_ARGS__)\n"; 924*5ffd83dbSDimitry Andric } else { 925*5ffd83dbSDimitry Andric std::string FullName = mangleName(ClassS); 926*5ffd83dbSDimitry Andric std::string ProtoName = mangleName(ClassG); 927*5ffd83dbSDimitry Andric 928*5ffd83dbSDimitry Andric OS << "__aio __attribute__((__clang_arm_builtin_alias(" 929*5ffd83dbSDimitry Andric << "__builtin_sve_" << FullName << ")))\n"; 930*5ffd83dbSDimitry Andric 931*5ffd83dbSDimitry Andric OS << getTypes()[0].str() << " " << ProtoName << "("; 932*5ffd83dbSDimitry Andric for (unsigned I = 0; I < getTypes().size() - 1; ++I) { 933*5ffd83dbSDimitry Andric if (I != 0) 934*5ffd83dbSDimitry Andric OS << ", "; 935*5ffd83dbSDimitry Andric OS << getTypes()[I + 1].str(); 936*5ffd83dbSDimitry Andric } 937*5ffd83dbSDimitry Andric OS << ");\n"; 938*5ffd83dbSDimitry Andric } 939*5ffd83dbSDimitry Andric } 940*5ffd83dbSDimitry Andric 941*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 942*5ffd83dbSDimitry Andric // SVEEmitter implementation 943*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 944*5ffd83dbSDimitry Andric uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) { 945*5ffd83dbSDimitry Andric if (T.isFloat()) { 946*5ffd83dbSDimitry Andric switch (T.getElementSizeInBits()) { 947*5ffd83dbSDimitry Andric case 16: 948*5ffd83dbSDimitry Andric return encodeEltType("EltTyFloat16"); 949*5ffd83dbSDimitry Andric case 32: 950*5ffd83dbSDimitry Andric return encodeEltType("EltTyFloat32"); 951*5ffd83dbSDimitry Andric case 64: 952*5ffd83dbSDimitry Andric return encodeEltType("EltTyFloat64"); 953*5ffd83dbSDimitry Andric default: 954*5ffd83dbSDimitry Andric llvm_unreachable("Unhandled float element bitwidth!"); 955*5ffd83dbSDimitry Andric } 956*5ffd83dbSDimitry Andric } 957*5ffd83dbSDimitry Andric 958*5ffd83dbSDimitry Andric if (T.isBFloat()) { 959*5ffd83dbSDimitry Andric assert(T.getElementSizeInBits() == 16 && "Not a valid BFloat."); 960*5ffd83dbSDimitry Andric return encodeEltType("EltTyBFloat16"); 961*5ffd83dbSDimitry Andric } 962*5ffd83dbSDimitry Andric 963*5ffd83dbSDimitry Andric if (T.isPredicateVector()) { 964*5ffd83dbSDimitry Andric switch (T.getElementSizeInBits()) { 965*5ffd83dbSDimitry Andric case 8: 966*5ffd83dbSDimitry Andric return encodeEltType("EltTyBool8"); 967*5ffd83dbSDimitry Andric case 16: 968*5ffd83dbSDimitry Andric return encodeEltType("EltTyBool16"); 969*5ffd83dbSDimitry Andric case 32: 970*5ffd83dbSDimitry Andric return encodeEltType("EltTyBool32"); 971*5ffd83dbSDimitry Andric case 64: 972*5ffd83dbSDimitry Andric return encodeEltType("EltTyBool64"); 973*5ffd83dbSDimitry Andric default: 974*5ffd83dbSDimitry Andric llvm_unreachable("Unhandled predicate element bitwidth!"); 975*5ffd83dbSDimitry Andric } 976*5ffd83dbSDimitry Andric } 977*5ffd83dbSDimitry Andric 978*5ffd83dbSDimitry Andric switch (T.getElementSizeInBits()) { 979*5ffd83dbSDimitry Andric case 8: 980*5ffd83dbSDimitry Andric return encodeEltType("EltTyInt8"); 981*5ffd83dbSDimitry Andric case 16: 982*5ffd83dbSDimitry Andric return encodeEltType("EltTyInt16"); 983*5ffd83dbSDimitry Andric case 32: 984*5ffd83dbSDimitry Andric return encodeEltType("EltTyInt32"); 985*5ffd83dbSDimitry Andric case 64: 986*5ffd83dbSDimitry Andric return encodeEltType("EltTyInt64"); 987*5ffd83dbSDimitry Andric default: 988*5ffd83dbSDimitry Andric llvm_unreachable("Unhandled integer element bitwidth!"); 989*5ffd83dbSDimitry Andric } 990*5ffd83dbSDimitry Andric } 991*5ffd83dbSDimitry Andric 992*5ffd83dbSDimitry Andric void SVEEmitter::createIntrinsic( 993*5ffd83dbSDimitry Andric Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) { 994*5ffd83dbSDimitry Andric StringRef Name = R->getValueAsString("Name"); 995*5ffd83dbSDimitry Andric StringRef Proto = R->getValueAsString("Prototype"); 996*5ffd83dbSDimitry Andric StringRef Types = R->getValueAsString("Types"); 997*5ffd83dbSDimitry Andric StringRef Guard = R->getValueAsString("ArchGuard"); 998*5ffd83dbSDimitry Andric StringRef LLVMName = R->getValueAsString("LLVMIntrinsic"); 999*5ffd83dbSDimitry Andric uint64_t Merge = R->getValueAsInt("Merge"); 1000*5ffd83dbSDimitry Andric StringRef MergeSuffix = R->getValueAsString("MergeSuffix"); 1001*5ffd83dbSDimitry Andric uint64_t MemEltType = R->getValueAsInt("MemEltType"); 1002*5ffd83dbSDimitry Andric std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags"); 1003*5ffd83dbSDimitry Andric std::vector<Record*> ImmCheckList = R->getValueAsListOfDefs("ImmChecks"); 1004*5ffd83dbSDimitry Andric 1005*5ffd83dbSDimitry Andric int64_t Flags = 0; 1006*5ffd83dbSDimitry Andric for (auto FlagRec : FlagsList) 1007*5ffd83dbSDimitry Andric Flags |= FlagRec->getValueAsInt("Value"); 1008*5ffd83dbSDimitry Andric 1009*5ffd83dbSDimitry Andric // Create a dummy TypeSpec for non-overloaded builtins. 1010*5ffd83dbSDimitry Andric if (Types.empty()) { 1011*5ffd83dbSDimitry Andric assert((Flags & getEnumValueForFlag("IsOverloadNone")) && 1012*5ffd83dbSDimitry Andric "Expect TypeSpec for overloaded builtin!"); 1013*5ffd83dbSDimitry Andric Types = "i"; 1014*5ffd83dbSDimitry Andric } 1015*5ffd83dbSDimitry Andric 1016*5ffd83dbSDimitry Andric // Extract type specs from string 1017*5ffd83dbSDimitry Andric SmallVector<TypeSpec, 8> TypeSpecs; 1018*5ffd83dbSDimitry Andric TypeSpec Acc; 1019*5ffd83dbSDimitry Andric for (char I : Types) { 1020*5ffd83dbSDimitry Andric Acc.push_back(I); 1021*5ffd83dbSDimitry Andric if (islower(I)) { 1022*5ffd83dbSDimitry Andric TypeSpecs.push_back(TypeSpec(Acc)); 1023*5ffd83dbSDimitry Andric Acc.clear(); 1024*5ffd83dbSDimitry Andric } 1025*5ffd83dbSDimitry Andric } 1026*5ffd83dbSDimitry Andric 1027*5ffd83dbSDimitry Andric // Remove duplicate type specs. 1028*5ffd83dbSDimitry Andric llvm::sort(TypeSpecs); 1029*5ffd83dbSDimitry Andric TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()), 1030*5ffd83dbSDimitry Andric TypeSpecs.end()); 1031*5ffd83dbSDimitry Andric 1032*5ffd83dbSDimitry Andric // Create an Intrinsic for each type spec. 1033*5ffd83dbSDimitry Andric for (auto TS : TypeSpecs) { 1034*5ffd83dbSDimitry Andric // Collate a list of range/option checks for the immediates. 1035*5ffd83dbSDimitry Andric SmallVector<ImmCheck, 2> ImmChecks; 1036*5ffd83dbSDimitry Andric for (auto *R : ImmCheckList) { 1037*5ffd83dbSDimitry Andric int64_t Arg = R->getValueAsInt("Arg"); 1038*5ffd83dbSDimitry Andric int64_t EltSizeArg = R->getValueAsInt("EltSizeArg"); 1039*5ffd83dbSDimitry Andric int64_t Kind = R->getValueAsDef("Kind")->getValueAsInt("Value"); 1040*5ffd83dbSDimitry Andric assert(Arg >= 0 && Kind >= 0 && "Arg and Kind must be nonnegative"); 1041*5ffd83dbSDimitry Andric 1042*5ffd83dbSDimitry Andric unsigned ElementSizeInBits = 0; 1043*5ffd83dbSDimitry Andric if (EltSizeArg >= 0) 1044*5ffd83dbSDimitry Andric ElementSizeInBits = 1045*5ffd83dbSDimitry Andric SVEType(TS, Proto[EltSizeArg + /* offset by return arg */ 1]) 1046*5ffd83dbSDimitry Andric .getElementSizeInBits(); 1047*5ffd83dbSDimitry Andric ImmChecks.push_back(ImmCheck(Arg, Kind, ElementSizeInBits)); 1048*5ffd83dbSDimitry Andric } 1049*5ffd83dbSDimitry Andric 1050*5ffd83dbSDimitry Andric Out.push_back(std::make_unique<Intrinsic>( 1051*5ffd83dbSDimitry Andric Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, ImmChecks, 1052*5ffd83dbSDimitry Andric TS, ClassS, *this, Guard)); 1053*5ffd83dbSDimitry Andric 1054*5ffd83dbSDimitry Andric // Also generate the short-form (e.g. svadd_m) for the given type-spec. 1055*5ffd83dbSDimitry Andric if (Intrinsic::isOverloadedIntrinsic(Name)) 1056*5ffd83dbSDimitry Andric Out.push_back(std::make_unique<Intrinsic>( 1057*5ffd83dbSDimitry Andric Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, 1058*5ffd83dbSDimitry Andric ImmChecks, TS, ClassG, *this, Guard)); 1059*5ffd83dbSDimitry Andric } 1060*5ffd83dbSDimitry Andric } 1061*5ffd83dbSDimitry Andric 1062*5ffd83dbSDimitry Andric void SVEEmitter::createHeader(raw_ostream &OS) { 1063*5ffd83dbSDimitry Andric OS << "/*===---- arm_sve.h - ARM SVE intrinsics " 1064*5ffd83dbSDimitry Andric "-----------------------------------===\n" 1065*5ffd83dbSDimitry Andric " *\n" 1066*5ffd83dbSDimitry Andric " *\n" 1067*5ffd83dbSDimitry Andric " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " 1068*5ffd83dbSDimitry Andric "Exceptions.\n" 1069*5ffd83dbSDimitry Andric " * See https://llvm.org/LICENSE.txt for license information.\n" 1070*5ffd83dbSDimitry Andric " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 1071*5ffd83dbSDimitry Andric " *\n" 1072*5ffd83dbSDimitry Andric " *===-----------------------------------------------------------------" 1073*5ffd83dbSDimitry Andric "------===\n" 1074*5ffd83dbSDimitry Andric " */\n\n"; 1075*5ffd83dbSDimitry Andric 1076*5ffd83dbSDimitry Andric OS << "#ifndef __ARM_SVE_H\n"; 1077*5ffd83dbSDimitry Andric OS << "#define __ARM_SVE_H\n\n"; 1078*5ffd83dbSDimitry Andric 1079*5ffd83dbSDimitry Andric OS << "#if !defined(__ARM_FEATURE_SVE)\n"; 1080*5ffd83dbSDimitry Andric OS << "#error \"SVE support not enabled\"\n"; 1081*5ffd83dbSDimitry Andric OS << "#else\n\n"; 1082*5ffd83dbSDimitry Andric 1083*5ffd83dbSDimitry Andric OS << "#if !defined(__LITTLE_ENDIAN__)\n"; 1084*5ffd83dbSDimitry Andric OS << "#error \"Big endian is currently not supported for arm_sve.h\"\n"; 1085*5ffd83dbSDimitry Andric OS << "#endif\n"; 1086*5ffd83dbSDimitry Andric 1087*5ffd83dbSDimitry Andric OS << "#include <stdint.h>\n\n"; 1088*5ffd83dbSDimitry Andric OS << "#ifdef __cplusplus\n"; 1089*5ffd83dbSDimitry Andric OS << "extern \"C\" {\n"; 1090*5ffd83dbSDimitry Andric OS << "#else\n"; 1091*5ffd83dbSDimitry Andric OS << "#include <stdbool.h>\n"; 1092*5ffd83dbSDimitry Andric OS << "#endif\n\n"; 1093*5ffd83dbSDimitry Andric 1094*5ffd83dbSDimitry Andric OS << "typedef __fp16 float16_t;\n"; 1095*5ffd83dbSDimitry Andric OS << "typedef float float32_t;\n"; 1096*5ffd83dbSDimitry Andric OS << "typedef double float64_t;\n"; 1097*5ffd83dbSDimitry Andric 1098*5ffd83dbSDimitry Andric OS << "typedef __SVInt8_t svint8_t;\n"; 1099*5ffd83dbSDimitry Andric OS << "typedef __SVInt16_t svint16_t;\n"; 1100*5ffd83dbSDimitry Andric OS << "typedef __SVInt32_t svint32_t;\n"; 1101*5ffd83dbSDimitry Andric OS << "typedef __SVInt64_t svint64_t;\n"; 1102*5ffd83dbSDimitry Andric OS << "typedef __SVUint8_t svuint8_t;\n"; 1103*5ffd83dbSDimitry Andric OS << "typedef __SVUint16_t svuint16_t;\n"; 1104*5ffd83dbSDimitry Andric OS << "typedef __SVUint32_t svuint32_t;\n"; 1105*5ffd83dbSDimitry Andric OS << "typedef __SVUint64_t svuint64_t;\n"; 1106*5ffd83dbSDimitry Andric OS << "typedef __SVFloat16_t svfloat16_t;\n\n"; 1107*5ffd83dbSDimitry Andric 1108*5ffd83dbSDimitry Andric OS << "#if defined(__ARM_FEATURE_SVE_BF16) && " 1109*5ffd83dbSDimitry Andric "!defined(__ARM_FEATURE_BF16_SCALAR_ARITHMETIC)\n"; 1110*5ffd83dbSDimitry Andric OS << "#error \"__ARM_FEATURE_BF16_SCALAR_ARITHMETIC must be defined when " 1111*5ffd83dbSDimitry Andric "__ARM_FEATURE_SVE_BF16 is defined\"\n"; 1112*5ffd83dbSDimitry Andric OS << "#endif\n\n"; 1113*5ffd83dbSDimitry Andric 1114*5ffd83dbSDimitry Andric OS << "#if defined(__ARM_FEATURE_SVE_BF16)\n"; 1115*5ffd83dbSDimitry Andric OS << "typedef __SVBFloat16_t svbfloat16_t;\n"; 1116*5ffd83dbSDimitry Andric OS << "#endif\n\n"; 1117*5ffd83dbSDimitry Andric 1118*5ffd83dbSDimitry Andric OS << "#if defined(__ARM_FEATURE_BF16_SCALAR_ARITHMETIC)\n"; 1119*5ffd83dbSDimitry Andric OS << "#include <arm_bf16.h>\n"; 1120*5ffd83dbSDimitry Andric OS << "typedef __bf16 bfloat16_t;\n"; 1121*5ffd83dbSDimitry Andric OS << "#endif\n\n"; 1122*5ffd83dbSDimitry Andric 1123*5ffd83dbSDimitry Andric OS << "typedef __SVFloat32_t svfloat32_t;\n"; 1124*5ffd83dbSDimitry Andric OS << "typedef __SVFloat64_t svfloat64_t;\n"; 1125*5ffd83dbSDimitry Andric OS << "typedef __clang_svint8x2_t svint8x2_t;\n"; 1126*5ffd83dbSDimitry Andric OS << "typedef __clang_svint16x2_t svint16x2_t;\n"; 1127*5ffd83dbSDimitry Andric OS << "typedef __clang_svint32x2_t svint32x2_t;\n"; 1128*5ffd83dbSDimitry Andric OS << "typedef __clang_svint64x2_t svint64x2_t;\n"; 1129*5ffd83dbSDimitry Andric OS << "typedef __clang_svuint8x2_t svuint8x2_t;\n"; 1130*5ffd83dbSDimitry Andric OS << "typedef __clang_svuint16x2_t svuint16x2_t;\n"; 1131*5ffd83dbSDimitry Andric OS << "typedef __clang_svuint32x2_t svuint32x2_t;\n"; 1132*5ffd83dbSDimitry Andric OS << "typedef __clang_svuint64x2_t svuint64x2_t;\n"; 1133*5ffd83dbSDimitry Andric OS << "typedef __clang_svfloat16x2_t svfloat16x2_t;\n"; 1134*5ffd83dbSDimitry Andric OS << "typedef __clang_svfloat32x2_t svfloat32x2_t;\n"; 1135*5ffd83dbSDimitry Andric OS << "typedef __clang_svfloat64x2_t svfloat64x2_t;\n"; 1136*5ffd83dbSDimitry Andric OS << "typedef __clang_svint8x3_t svint8x3_t;\n"; 1137*5ffd83dbSDimitry Andric OS << "typedef __clang_svint16x3_t svint16x3_t;\n"; 1138*5ffd83dbSDimitry Andric OS << "typedef __clang_svint32x3_t svint32x3_t;\n"; 1139*5ffd83dbSDimitry Andric OS << "typedef __clang_svint64x3_t svint64x3_t;\n"; 1140*5ffd83dbSDimitry Andric OS << "typedef __clang_svuint8x3_t svuint8x3_t;\n"; 1141*5ffd83dbSDimitry Andric OS << "typedef __clang_svuint16x3_t svuint16x3_t;\n"; 1142*5ffd83dbSDimitry Andric OS << "typedef __clang_svuint32x3_t svuint32x3_t;\n"; 1143*5ffd83dbSDimitry Andric OS << "typedef __clang_svuint64x3_t svuint64x3_t;\n"; 1144*5ffd83dbSDimitry Andric OS << "typedef __clang_svfloat16x3_t svfloat16x3_t;\n"; 1145*5ffd83dbSDimitry Andric OS << "typedef __clang_svfloat32x3_t svfloat32x3_t;\n"; 1146*5ffd83dbSDimitry Andric OS << "typedef __clang_svfloat64x3_t svfloat64x3_t;\n"; 1147*5ffd83dbSDimitry Andric OS << "typedef __clang_svint8x4_t svint8x4_t;\n"; 1148*5ffd83dbSDimitry Andric OS << "typedef __clang_svint16x4_t svint16x4_t;\n"; 1149*5ffd83dbSDimitry Andric OS << "typedef __clang_svint32x4_t svint32x4_t;\n"; 1150*5ffd83dbSDimitry Andric OS << "typedef __clang_svint64x4_t svint64x4_t;\n"; 1151*5ffd83dbSDimitry Andric OS << "typedef __clang_svuint8x4_t svuint8x4_t;\n"; 1152*5ffd83dbSDimitry Andric OS << "typedef __clang_svuint16x4_t svuint16x4_t;\n"; 1153*5ffd83dbSDimitry Andric OS << "typedef __clang_svuint32x4_t svuint32x4_t;\n"; 1154*5ffd83dbSDimitry Andric OS << "typedef __clang_svuint64x4_t svuint64x4_t;\n"; 1155*5ffd83dbSDimitry Andric OS << "typedef __clang_svfloat16x4_t svfloat16x4_t;\n"; 1156*5ffd83dbSDimitry Andric OS << "typedef __clang_svfloat32x4_t svfloat32x4_t;\n"; 1157*5ffd83dbSDimitry Andric OS << "typedef __clang_svfloat64x4_t svfloat64x4_t;\n"; 1158*5ffd83dbSDimitry Andric OS << "typedef __SVBool_t svbool_t;\n\n"; 1159*5ffd83dbSDimitry Andric 1160*5ffd83dbSDimitry Andric OS << "#ifdef __ARM_FEATURE_SVE_BF16\n"; 1161*5ffd83dbSDimitry Andric OS << "typedef __clang_svbfloat16x2_t svbfloat16x2_t;\n"; 1162*5ffd83dbSDimitry Andric OS << "typedef __clang_svbfloat16x3_t svbfloat16x3_t;\n"; 1163*5ffd83dbSDimitry Andric OS << "typedef __clang_svbfloat16x4_t svbfloat16x4_t;\n"; 1164*5ffd83dbSDimitry Andric OS << "#endif\n"; 1165*5ffd83dbSDimitry Andric 1166*5ffd83dbSDimitry Andric OS << "typedef enum\n"; 1167*5ffd83dbSDimitry Andric OS << "{\n"; 1168*5ffd83dbSDimitry Andric OS << " SV_POW2 = 0,\n"; 1169*5ffd83dbSDimitry Andric OS << " SV_VL1 = 1,\n"; 1170*5ffd83dbSDimitry Andric OS << " SV_VL2 = 2,\n"; 1171*5ffd83dbSDimitry Andric OS << " SV_VL3 = 3,\n"; 1172*5ffd83dbSDimitry Andric OS << " SV_VL4 = 4,\n"; 1173*5ffd83dbSDimitry Andric OS << " SV_VL5 = 5,\n"; 1174*5ffd83dbSDimitry Andric OS << " SV_VL6 = 6,\n"; 1175*5ffd83dbSDimitry Andric OS << " SV_VL7 = 7,\n"; 1176*5ffd83dbSDimitry Andric OS << " SV_VL8 = 8,\n"; 1177*5ffd83dbSDimitry Andric OS << " SV_VL16 = 9,\n"; 1178*5ffd83dbSDimitry Andric OS << " SV_VL32 = 10,\n"; 1179*5ffd83dbSDimitry Andric OS << " SV_VL64 = 11,\n"; 1180*5ffd83dbSDimitry Andric OS << " SV_VL128 = 12,\n"; 1181*5ffd83dbSDimitry Andric OS << " SV_VL256 = 13,\n"; 1182*5ffd83dbSDimitry Andric OS << " SV_MUL4 = 29,\n"; 1183*5ffd83dbSDimitry Andric OS << " SV_MUL3 = 30,\n"; 1184*5ffd83dbSDimitry Andric OS << " SV_ALL = 31\n"; 1185*5ffd83dbSDimitry Andric OS << "} sv_pattern;\n\n"; 1186*5ffd83dbSDimitry Andric 1187*5ffd83dbSDimitry Andric OS << "typedef enum\n"; 1188*5ffd83dbSDimitry Andric OS << "{\n"; 1189*5ffd83dbSDimitry Andric OS << " SV_PLDL1KEEP = 0,\n"; 1190*5ffd83dbSDimitry Andric OS << " SV_PLDL1STRM = 1,\n"; 1191*5ffd83dbSDimitry Andric OS << " SV_PLDL2KEEP = 2,\n"; 1192*5ffd83dbSDimitry Andric OS << " SV_PLDL2STRM = 3,\n"; 1193*5ffd83dbSDimitry Andric OS << " SV_PLDL3KEEP = 4,\n"; 1194*5ffd83dbSDimitry Andric OS << " SV_PLDL3STRM = 5,\n"; 1195*5ffd83dbSDimitry Andric OS << " SV_PSTL1KEEP = 8,\n"; 1196*5ffd83dbSDimitry Andric OS << " SV_PSTL1STRM = 9,\n"; 1197*5ffd83dbSDimitry Andric OS << " SV_PSTL2KEEP = 10,\n"; 1198*5ffd83dbSDimitry Andric OS << " SV_PSTL2STRM = 11,\n"; 1199*5ffd83dbSDimitry Andric OS << " SV_PSTL3KEEP = 12,\n"; 1200*5ffd83dbSDimitry Andric OS << " SV_PSTL3STRM = 13\n"; 1201*5ffd83dbSDimitry Andric OS << "} sv_prfop;\n\n"; 1202*5ffd83dbSDimitry Andric 1203*5ffd83dbSDimitry Andric OS << "/* Function attributes */\n"; 1204*5ffd83dbSDimitry Andric OS << "#define __aio static inline __attribute__((__always_inline__, " 1205*5ffd83dbSDimitry Andric "__nodebug__, __overloadable__))\n\n"; 1206*5ffd83dbSDimitry Andric 1207*5ffd83dbSDimitry Andric // Add reinterpret functions. 1208*5ffd83dbSDimitry Andric for (auto ShortForm : { false, true } ) 1209*5ffd83dbSDimitry Andric for (const ReinterpretTypeInfo &From : Reinterprets) 1210*5ffd83dbSDimitry Andric for (const ReinterpretTypeInfo &To : Reinterprets) { 1211*5ffd83dbSDimitry Andric const bool IsBFloat = StringRef(From.Suffix).equals("bf16") || 1212*5ffd83dbSDimitry Andric StringRef(To.Suffix).equals("bf16"); 1213*5ffd83dbSDimitry Andric if (IsBFloat) 1214*5ffd83dbSDimitry Andric OS << "#if defined(__ARM_FEATURE_SVE_BF16)\n"; 1215*5ffd83dbSDimitry Andric if (ShortForm) { 1216*5ffd83dbSDimitry Andric OS << "__aio " << From.Type << " svreinterpret_" << From.Suffix; 1217*5ffd83dbSDimitry Andric OS << "(" << To.Type << " op) {\n"; 1218*5ffd83dbSDimitry Andric OS << " return __builtin_sve_reinterpret_" << From.Suffix << "_" 1219*5ffd83dbSDimitry Andric << To.Suffix << "(op);\n"; 1220*5ffd83dbSDimitry Andric OS << "}\n\n"; 1221*5ffd83dbSDimitry Andric } else 1222*5ffd83dbSDimitry Andric OS << "#define svreinterpret_" << From.Suffix << "_" << To.Suffix 1223*5ffd83dbSDimitry Andric << "(...) __builtin_sve_reinterpret_" << From.Suffix << "_" 1224*5ffd83dbSDimitry Andric << To.Suffix << "(__VA_ARGS__)\n"; 1225*5ffd83dbSDimitry Andric if (IsBFloat) 1226*5ffd83dbSDimitry Andric OS << "#endif /* #if defined(__ARM_FEATURE_SVE_BF16) */\n"; 1227*5ffd83dbSDimitry Andric } 1228*5ffd83dbSDimitry Andric 1229*5ffd83dbSDimitry Andric SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 1230*5ffd83dbSDimitry Andric std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 1231*5ffd83dbSDimitry Andric for (auto *R : RV) 1232*5ffd83dbSDimitry Andric createIntrinsic(R, Defs); 1233*5ffd83dbSDimitry Andric 1234*5ffd83dbSDimitry Andric // Sort intrinsics in header file by following order/priority: 1235*5ffd83dbSDimitry Andric // - Architectural guard (i.e. does it require SVE2 or SVE2_AES) 1236*5ffd83dbSDimitry Andric // - Class (is intrinsic overloaded or not) 1237*5ffd83dbSDimitry Andric // - Intrinsic name 1238*5ffd83dbSDimitry Andric std::stable_sort( 1239*5ffd83dbSDimitry Andric Defs.begin(), Defs.end(), [](const std::unique_ptr<Intrinsic> &A, 1240*5ffd83dbSDimitry Andric const std::unique_ptr<Intrinsic> &B) { 1241*5ffd83dbSDimitry Andric auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) { 1242*5ffd83dbSDimitry Andric return std::make_tuple(I->getGuard(), (unsigned)I->getClassKind(), I->getName()); 1243*5ffd83dbSDimitry Andric }; 1244*5ffd83dbSDimitry Andric return ToTuple(A) < ToTuple(B); 1245*5ffd83dbSDimitry Andric }); 1246*5ffd83dbSDimitry Andric 1247*5ffd83dbSDimitry Andric StringRef InGuard = ""; 1248*5ffd83dbSDimitry Andric for (auto &I : Defs) { 1249*5ffd83dbSDimitry Andric // Emit #endif/#if pair if needed. 1250*5ffd83dbSDimitry Andric if (I->getGuard() != InGuard) { 1251*5ffd83dbSDimitry Andric if (!InGuard.empty()) 1252*5ffd83dbSDimitry Andric OS << "#endif //" << InGuard << "\n"; 1253*5ffd83dbSDimitry Andric InGuard = I->getGuard(); 1254*5ffd83dbSDimitry Andric if (!InGuard.empty()) 1255*5ffd83dbSDimitry Andric OS << "\n#if " << InGuard << "\n"; 1256*5ffd83dbSDimitry Andric } 1257*5ffd83dbSDimitry Andric 1258*5ffd83dbSDimitry Andric // Actually emit the intrinsic declaration. 1259*5ffd83dbSDimitry Andric I->emitIntrinsic(OS); 1260*5ffd83dbSDimitry Andric } 1261*5ffd83dbSDimitry Andric 1262*5ffd83dbSDimitry Andric if (!InGuard.empty()) 1263*5ffd83dbSDimitry Andric OS << "#endif //" << InGuard << "\n"; 1264*5ffd83dbSDimitry Andric 1265*5ffd83dbSDimitry Andric OS << "#if defined(__ARM_FEATURE_SVE_BF16)\n"; 1266*5ffd83dbSDimitry Andric OS << "#define svcvtnt_bf16_x svcvtnt_bf16_m\n"; 1267*5ffd83dbSDimitry Andric OS << "#define svcvtnt_bf16_f32_x svcvtnt_bf16_f32_m\n"; 1268*5ffd83dbSDimitry Andric OS << "#endif /*__ARM_FEATURE_SVE_BF16 */\n\n"; 1269*5ffd83dbSDimitry Andric 1270*5ffd83dbSDimitry Andric OS << "#if defined(__ARM_FEATURE_SVE2)\n"; 1271*5ffd83dbSDimitry Andric OS << "#define svcvtnt_f16_x svcvtnt_f16_m\n"; 1272*5ffd83dbSDimitry Andric OS << "#define svcvtnt_f16_f32_x svcvtnt_f16_f32_m\n"; 1273*5ffd83dbSDimitry Andric OS << "#define svcvtnt_f32_x svcvtnt_f32_m\n"; 1274*5ffd83dbSDimitry Andric OS << "#define svcvtnt_f32_f64_x svcvtnt_f32_f64_m\n\n"; 1275*5ffd83dbSDimitry Andric 1276*5ffd83dbSDimitry Andric OS << "#define svcvtxnt_f32_x svcvtxnt_f32_m\n"; 1277*5ffd83dbSDimitry Andric OS << "#define svcvtxnt_f32_f64_x svcvtxnt_f32_f64_m\n\n"; 1278*5ffd83dbSDimitry Andric 1279*5ffd83dbSDimitry Andric OS << "#endif /*__ARM_FEATURE_SVE2 */\n\n"; 1280*5ffd83dbSDimitry Andric 1281*5ffd83dbSDimitry Andric OS << "#ifdef __cplusplus\n"; 1282*5ffd83dbSDimitry Andric OS << "} // extern \"C\"\n"; 1283*5ffd83dbSDimitry Andric OS << "#endif\n\n"; 1284*5ffd83dbSDimitry Andric OS << "#endif /*__ARM_FEATURE_SVE */\n\n"; 1285*5ffd83dbSDimitry Andric OS << "#endif /* __ARM_SVE_H */\n"; 1286*5ffd83dbSDimitry Andric } 1287*5ffd83dbSDimitry Andric 1288*5ffd83dbSDimitry Andric void SVEEmitter::createBuiltins(raw_ostream &OS) { 1289*5ffd83dbSDimitry Andric std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 1290*5ffd83dbSDimitry Andric SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 1291*5ffd83dbSDimitry Andric for (auto *R : RV) 1292*5ffd83dbSDimitry Andric createIntrinsic(R, Defs); 1293*5ffd83dbSDimitry Andric 1294*5ffd83dbSDimitry Andric // The mappings must be sorted based on BuiltinID. 1295*5ffd83dbSDimitry Andric llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 1296*5ffd83dbSDimitry Andric const std::unique_ptr<Intrinsic> &B) { 1297*5ffd83dbSDimitry Andric return A->getMangledName() < B->getMangledName(); 1298*5ffd83dbSDimitry Andric }); 1299*5ffd83dbSDimitry Andric 1300*5ffd83dbSDimitry Andric OS << "#ifdef GET_SVE_BUILTINS\n"; 1301*5ffd83dbSDimitry Andric for (auto &Def : Defs) { 1302*5ffd83dbSDimitry Andric // Only create BUILTINs for non-overloaded intrinsics, as overloaded 1303*5ffd83dbSDimitry Andric // declarations only live in the header file. 1304*5ffd83dbSDimitry Andric if (Def->getClassKind() != ClassG) 1305*5ffd83dbSDimitry Andric OS << "BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \"" 1306*5ffd83dbSDimitry Andric << Def->getBuiltinTypeStr() << "\", \"n\")\n"; 1307*5ffd83dbSDimitry Andric } 1308*5ffd83dbSDimitry Andric 1309*5ffd83dbSDimitry Andric // Add reinterpret builtins 1310*5ffd83dbSDimitry Andric for (const ReinterpretTypeInfo &From : Reinterprets) 1311*5ffd83dbSDimitry Andric for (const ReinterpretTypeInfo &To : Reinterprets) 1312*5ffd83dbSDimitry Andric OS << "BUILTIN(__builtin_sve_reinterpret_" << From.Suffix << "_" 1313*5ffd83dbSDimitry Andric << To.Suffix << +", \"" << From.BuiltinType << To.BuiltinType 1314*5ffd83dbSDimitry Andric << "\", \"n\")\n"; 1315*5ffd83dbSDimitry Andric 1316*5ffd83dbSDimitry Andric OS << "#endif\n\n"; 1317*5ffd83dbSDimitry Andric } 1318*5ffd83dbSDimitry Andric 1319*5ffd83dbSDimitry Andric void SVEEmitter::createCodeGenMap(raw_ostream &OS) { 1320*5ffd83dbSDimitry Andric std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 1321*5ffd83dbSDimitry Andric SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 1322*5ffd83dbSDimitry Andric for (auto *R : RV) 1323*5ffd83dbSDimitry Andric createIntrinsic(R, Defs); 1324*5ffd83dbSDimitry Andric 1325*5ffd83dbSDimitry Andric // The mappings must be sorted based on BuiltinID. 1326*5ffd83dbSDimitry Andric llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 1327*5ffd83dbSDimitry Andric const std::unique_ptr<Intrinsic> &B) { 1328*5ffd83dbSDimitry Andric return A->getMangledName() < B->getMangledName(); 1329*5ffd83dbSDimitry Andric }); 1330*5ffd83dbSDimitry Andric 1331*5ffd83dbSDimitry Andric OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n"; 1332*5ffd83dbSDimitry Andric for (auto &Def : Defs) { 1333*5ffd83dbSDimitry Andric // Builtins only exist for non-overloaded intrinsics, overloaded 1334*5ffd83dbSDimitry Andric // declarations only live in the header file. 1335*5ffd83dbSDimitry Andric if (Def->getClassKind() == ClassG) 1336*5ffd83dbSDimitry Andric continue; 1337*5ffd83dbSDimitry Andric 1338*5ffd83dbSDimitry Andric uint64_t Flags = Def->getFlags(); 1339*5ffd83dbSDimitry Andric auto FlagString = std::to_string(Flags); 1340*5ffd83dbSDimitry Andric 1341*5ffd83dbSDimitry Andric std::string LLVMName = Def->getLLVMName(); 1342*5ffd83dbSDimitry Andric std::string Builtin = Def->getMangledName(); 1343*5ffd83dbSDimitry Andric if (!LLVMName.empty()) 1344*5ffd83dbSDimitry Andric OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString 1345*5ffd83dbSDimitry Andric << "),\n"; 1346*5ffd83dbSDimitry Andric else 1347*5ffd83dbSDimitry Andric OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n"; 1348*5ffd83dbSDimitry Andric } 1349*5ffd83dbSDimitry Andric OS << "#endif\n\n"; 1350*5ffd83dbSDimitry Andric } 1351*5ffd83dbSDimitry Andric 1352*5ffd83dbSDimitry Andric void SVEEmitter::createRangeChecks(raw_ostream &OS) { 1353*5ffd83dbSDimitry Andric std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 1354*5ffd83dbSDimitry Andric SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; 1355*5ffd83dbSDimitry Andric for (auto *R : RV) 1356*5ffd83dbSDimitry Andric createIntrinsic(R, Defs); 1357*5ffd83dbSDimitry Andric 1358*5ffd83dbSDimitry Andric // The mappings must be sorted based on BuiltinID. 1359*5ffd83dbSDimitry Andric llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, 1360*5ffd83dbSDimitry Andric const std::unique_ptr<Intrinsic> &B) { 1361*5ffd83dbSDimitry Andric return A->getMangledName() < B->getMangledName(); 1362*5ffd83dbSDimitry Andric }); 1363*5ffd83dbSDimitry Andric 1364*5ffd83dbSDimitry Andric 1365*5ffd83dbSDimitry Andric OS << "#ifdef GET_SVE_IMMEDIATE_CHECK\n"; 1366*5ffd83dbSDimitry Andric 1367*5ffd83dbSDimitry Andric // Ensure these are only emitted once. 1368*5ffd83dbSDimitry Andric std::set<std::string> Emitted; 1369*5ffd83dbSDimitry Andric 1370*5ffd83dbSDimitry Andric for (auto &Def : Defs) { 1371*5ffd83dbSDimitry Andric if (Emitted.find(Def->getMangledName()) != Emitted.end() || 1372*5ffd83dbSDimitry Andric Def->getImmChecks().empty()) 1373*5ffd83dbSDimitry Andric continue; 1374*5ffd83dbSDimitry Andric 1375*5ffd83dbSDimitry Andric OS << "case SVE::BI__builtin_sve_" << Def->getMangledName() << ":\n"; 1376*5ffd83dbSDimitry Andric for (auto &Check : Def->getImmChecks()) 1377*5ffd83dbSDimitry Andric OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", " 1378*5ffd83dbSDimitry Andric << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n"; 1379*5ffd83dbSDimitry Andric OS << " break;\n"; 1380*5ffd83dbSDimitry Andric 1381*5ffd83dbSDimitry Andric Emitted.insert(Def->getMangledName()); 1382*5ffd83dbSDimitry Andric } 1383*5ffd83dbSDimitry Andric 1384*5ffd83dbSDimitry Andric OS << "#endif\n\n"; 1385*5ffd83dbSDimitry Andric } 1386*5ffd83dbSDimitry Andric 1387*5ffd83dbSDimitry Andric /// Create the SVETypeFlags used in CGBuiltins 1388*5ffd83dbSDimitry Andric void SVEEmitter::createTypeFlags(raw_ostream &OS) { 1389*5ffd83dbSDimitry Andric OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n"; 1390*5ffd83dbSDimitry Andric for (auto &KV : FlagTypes) 1391*5ffd83dbSDimitry Andric OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n"; 1392*5ffd83dbSDimitry Andric OS << "#endif\n\n"; 1393*5ffd83dbSDimitry Andric 1394*5ffd83dbSDimitry Andric OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n"; 1395*5ffd83dbSDimitry Andric for (auto &KV : EltTypes) 1396*5ffd83dbSDimitry Andric OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; 1397*5ffd83dbSDimitry Andric OS << "#endif\n\n"; 1398*5ffd83dbSDimitry Andric 1399*5ffd83dbSDimitry Andric OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n"; 1400*5ffd83dbSDimitry Andric for (auto &KV : MemEltTypes) 1401*5ffd83dbSDimitry Andric OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; 1402*5ffd83dbSDimitry Andric OS << "#endif\n\n"; 1403*5ffd83dbSDimitry Andric 1404*5ffd83dbSDimitry Andric OS << "#ifdef LLVM_GET_SVE_MERGETYPES\n"; 1405*5ffd83dbSDimitry Andric for (auto &KV : MergeTypes) 1406*5ffd83dbSDimitry Andric OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; 1407*5ffd83dbSDimitry Andric OS << "#endif\n\n"; 1408*5ffd83dbSDimitry Andric 1409*5ffd83dbSDimitry Andric OS << "#ifdef LLVM_GET_SVE_IMMCHECKTYPES\n"; 1410*5ffd83dbSDimitry Andric for (auto &KV : ImmCheckTypes) 1411*5ffd83dbSDimitry Andric OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; 1412*5ffd83dbSDimitry Andric OS << "#endif\n\n"; 1413*5ffd83dbSDimitry Andric } 1414*5ffd83dbSDimitry Andric 1415*5ffd83dbSDimitry Andric namespace clang { 1416*5ffd83dbSDimitry Andric void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) { 1417*5ffd83dbSDimitry Andric SVEEmitter(Records).createHeader(OS); 1418*5ffd83dbSDimitry Andric } 1419*5ffd83dbSDimitry Andric 1420*5ffd83dbSDimitry Andric void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) { 1421*5ffd83dbSDimitry Andric SVEEmitter(Records).createBuiltins(OS); 1422*5ffd83dbSDimitry Andric } 1423*5ffd83dbSDimitry Andric 1424*5ffd83dbSDimitry Andric void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 1425*5ffd83dbSDimitry Andric SVEEmitter(Records).createCodeGenMap(OS); 1426*5ffd83dbSDimitry Andric } 1427*5ffd83dbSDimitry Andric 1428*5ffd83dbSDimitry Andric void EmitSveRangeChecks(RecordKeeper &Records, raw_ostream &OS) { 1429*5ffd83dbSDimitry Andric SVEEmitter(Records).createRangeChecks(OS); 1430*5ffd83dbSDimitry Andric } 1431*5ffd83dbSDimitry Andric 1432*5ffd83dbSDimitry Andric void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) { 1433*5ffd83dbSDimitry Andric SVEEmitter(Records).createTypeFlags(OS); 1434*5ffd83dbSDimitry Andric } 1435*5ffd83dbSDimitry Andric 1436*5ffd83dbSDimitry Andric } // End namespace clang 1437