1*fe6060f1SDimitry Andric //===- RISCVVEmitter.cpp - Generate riscv_vector.h for use with clang -----===// 2*fe6060f1SDimitry Andric // 3*fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*fe6060f1SDimitry Andric // 7*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8*fe6060f1SDimitry Andric // 9*fe6060f1SDimitry Andric // This tablegen backend is responsible for emitting riscv_vector.h which 10*fe6060f1SDimitry Andric // includes a declaration and definition of each intrinsic functions specified 11*fe6060f1SDimitry Andric // in https://github.com/riscv/rvv-intrinsic-doc. 12*fe6060f1SDimitry Andric // 13*fe6060f1SDimitry Andric // See also the documentation in include/clang/Basic/riscv_vector.td. 14*fe6060f1SDimitry Andric // 15*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 16*fe6060f1SDimitry Andric 17*fe6060f1SDimitry Andric #include "llvm/ADT/ArrayRef.h" 18*fe6060f1SDimitry Andric #include "llvm/ADT/SmallSet.h" 19*fe6060f1SDimitry Andric #include "llvm/ADT/StringExtras.h" 20*fe6060f1SDimitry Andric #include "llvm/ADT/StringMap.h" 21*fe6060f1SDimitry Andric #include "llvm/ADT/StringSet.h" 22*fe6060f1SDimitry Andric #include "llvm/ADT/Twine.h" 23*fe6060f1SDimitry Andric #include "llvm/TableGen/Error.h" 24*fe6060f1SDimitry Andric #include "llvm/TableGen/Record.h" 25*fe6060f1SDimitry Andric #include <numeric> 26*fe6060f1SDimitry Andric 27*fe6060f1SDimitry Andric using namespace llvm; 28*fe6060f1SDimitry Andric using BasicType = char; 29*fe6060f1SDimitry Andric using VScaleVal = Optional<unsigned>; 30*fe6060f1SDimitry Andric 31*fe6060f1SDimitry Andric namespace { 32*fe6060f1SDimitry Andric 33*fe6060f1SDimitry Andric // Exponential LMUL 34*fe6060f1SDimitry Andric struct LMULType { 35*fe6060f1SDimitry Andric int Log2LMUL; 36*fe6060f1SDimitry Andric LMULType(int Log2LMUL); 37*fe6060f1SDimitry Andric // Return the C/C++ string representation of LMUL 38*fe6060f1SDimitry Andric std::string str() const; 39*fe6060f1SDimitry Andric Optional<unsigned> getScale(unsigned ElementBitwidth) const; 40*fe6060f1SDimitry Andric void MulLog2LMUL(int Log2LMUL); 41*fe6060f1SDimitry Andric LMULType &operator*=(uint32_t RHS); 42*fe6060f1SDimitry Andric }; 43*fe6060f1SDimitry Andric 44*fe6060f1SDimitry Andric // This class is compact representation of a valid and invalid RVVType. 45*fe6060f1SDimitry Andric class RVVType { 46*fe6060f1SDimitry Andric enum ScalarTypeKind : uint32_t { 47*fe6060f1SDimitry Andric Void, 48*fe6060f1SDimitry Andric Size_t, 49*fe6060f1SDimitry Andric Ptrdiff_t, 50*fe6060f1SDimitry Andric UnsignedLong, 51*fe6060f1SDimitry Andric SignedLong, 52*fe6060f1SDimitry Andric Boolean, 53*fe6060f1SDimitry Andric SignedInteger, 54*fe6060f1SDimitry Andric UnsignedInteger, 55*fe6060f1SDimitry Andric Float, 56*fe6060f1SDimitry Andric Invalid, 57*fe6060f1SDimitry Andric }; 58*fe6060f1SDimitry Andric BasicType BT; 59*fe6060f1SDimitry Andric ScalarTypeKind ScalarType = Invalid; 60*fe6060f1SDimitry Andric LMULType LMUL; 61*fe6060f1SDimitry Andric bool IsPointer = false; 62*fe6060f1SDimitry Andric // IsConstant indices are "int", but have the constant expression. 63*fe6060f1SDimitry Andric bool IsImmediate = false; 64*fe6060f1SDimitry Andric // Const qualifier for pointer to const object or object of const type. 65*fe6060f1SDimitry Andric bool IsConstant = false; 66*fe6060f1SDimitry Andric unsigned ElementBitwidth = 0; 67*fe6060f1SDimitry Andric VScaleVal Scale = 0; 68*fe6060f1SDimitry Andric bool Valid; 69*fe6060f1SDimitry Andric 70*fe6060f1SDimitry Andric std::string BuiltinStr; 71*fe6060f1SDimitry Andric std::string ClangBuiltinStr; 72*fe6060f1SDimitry Andric std::string Str; 73*fe6060f1SDimitry Andric std::string ShortStr; 74*fe6060f1SDimitry Andric 75*fe6060f1SDimitry Andric public: 76*fe6060f1SDimitry Andric RVVType() : RVVType(BasicType(), 0, StringRef()) {} 77*fe6060f1SDimitry Andric RVVType(BasicType BT, int Log2LMUL, StringRef prototype); 78*fe6060f1SDimitry Andric 79*fe6060f1SDimitry Andric // Return the string representation of a type, which is an encoded string for 80*fe6060f1SDimitry Andric // passing to the BUILTIN() macro in Builtins.def. 81*fe6060f1SDimitry Andric const std::string &getBuiltinStr() const { return BuiltinStr; } 82*fe6060f1SDimitry Andric 83*fe6060f1SDimitry Andric // Return the clang buitlin type for RVV vector type which are used in the 84*fe6060f1SDimitry Andric // riscv_vector.h header file. 85*fe6060f1SDimitry Andric const std::string &getClangBuiltinStr() const { return ClangBuiltinStr; } 86*fe6060f1SDimitry Andric 87*fe6060f1SDimitry Andric // Return the C/C++ string representation of a type for use in the 88*fe6060f1SDimitry Andric // riscv_vector.h header file. 89*fe6060f1SDimitry Andric const std::string &getTypeStr() const { return Str; } 90*fe6060f1SDimitry Andric 91*fe6060f1SDimitry Andric // Return the short name of a type for C/C++ name suffix. 92*fe6060f1SDimitry Andric const std::string &getShortStr() { 93*fe6060f1SDimitry Andric // Not all types are used in short name, so compute the short name by 94*fe6060f1SDimitry Andric // demanded. 95*fe6060f1SDimitry Andric if (ShortStr.empty()) 96*fe6060f1SDimitry Andric initShortStr(); 97*fe6060f1SDimitry Andric return ShortStr; 98*fe6060f1SDimitry Andric } 99*fe6060f1SDimitry Andric 100*fe6060f1SDimitry Andric bool isValid() const { return Valid; } 101*fe6060f1SDimitry Andric bool isScalar() const { return Scale.hasValue() && Scale.getValue() == 0; } 102*fe6060f1SDimitry Andric bool isVector() const { return Scale.hasValue() && Scale.getValue() != 0; } 103*fe6060f1SDimitry Andric bool isFloat() const { return ScalarType == ScalarTypeKind::Float; } 104*fe6060f1SDimitry Andric bool isSignedInteger() const { 105*fe6060f1SDimitry Andric return ScalarType == ScalarTypeKind::SignedInteger; 106*fe6060f1SDimitry Andric } 107*fe6060f1SDimitry Andric bool isFloatVector(unsigned Width) const { 108*fe6060f1SDimitry Andric return isVector() && isFloat() && ElementBitwidth == Width; 109*fe6060f1SDimitry Andric } 110*fe6060f1SDimitry Andric bool isFloat(unsigned Width) const { 111*fe6060f1SDimitry Andric return isFloat() && ElementBitwidth == Width; 112*fe6060f1SDimitry Andric } 113*fe6060f1SDimitry Andric 114*fe6060f1SDimitry Andric private: 115*fe6060f1SDimitry Andric // Verify RVV vector type and set Valid. 116*fe6060f1SDimitry Andric bool verifyType() const; 117*fe6060f1SDimitry Andric 118*fe6060f1SDimitry Andric // Creates a type based on basic types of TypeRange 119*fe6060f1SDimitry Andric void applyBasicType(); 120*fe6060f1SDimitry Andric 121*fe6060f1SDimitry Andric // Applies a prototype modifier to the current type. The result maybe an 122*fe6060f1SDimitry Andric // invalid type. 123*fe6060f1SDimitry Andric void applyModifier(StringRef prototype); 124*fe6060f1SDimitry Andric 125*fe6060f1SDimitry Andric // Compute and record a string for legal type. 126*fe6060f1SDimitry Andric void initBuiltinStr(); 127*fe6060f1SDimitry Andric // Compute and record a builtin RVV vector type string. 128*fe6060f1SDimitry Andric void initClangBuiltinStr(); 129*fe6060f1SDimitry Andric // Compute and record a type string for used in the header. 130*fe6060f1SDimitry Andric void initTypeStr(); 131*fe6060f1SDimitry Andric // Compute and record a short name of a type for C/C++ name suffix. 132*fe6060f1SDimitry Andric void initShortStr(); 133*fe6060f1SDimitry Andric }; 134*fe6060f1SDimitry Andric 135*fe6060f1SDimitry Andric using RVVTypePtr = RVVType *; 136*fe6060f1SDimitry Andric using RVVTypes = std::vector<RVVTypePtr>; 137*fe6060f1SDimitry Andric 138*fe6060f1SDimitry Andric enum RISCVExtension : uint8_t { 139*fe6060f1SDimitry Andric Basic = 0, 140*fe6060f1SDimitry Andric F = 1 << 1, 141*fe6060f1SDimitry Andric D = 1 << 2, 142*fe6060f1SDimitry Andric Zfh = 1 << 3, 143*fe6060f1SDimitry Andric Zvamo = 1 << 4, 144*fe6060f1SDimitry Andric Zvlsseg = 1 << 5, 145*fe6060f1SDimitry Andric }; 146*fe6060f1SDimitry Andric 147*fe6060f1SDimitry Andric // TODO refactor RVVIntrinsic class design after support all intrinsic 148*fe6060f1SDimitry Andric // combination. This represents an instantiation of an intrinsic with a 149*fe6060f1SDimitry Andric // particular type and prototype 150*fe6060f1SDimitry Andric class RVVIntrinsic { 151*fe6060f1SDimitry Andric 152*fe6060f1SDimitry Andric private: 153*fe6060f1SDimitry Andric std::string Name; // Builtin name 154*fe6060f1SDimitry Andric std::string MangledName; 155*fe6060f1SDimitry Andric std::string IRName; 156*fe6060f1SDimitry Andric bool HasSideEffects; 157*fe6060f1SDimitry Andric bool IsMask; 158*fe6060f1SDimitry Andric bool HasMaskedOffOperand; 159*fe6060f1SDimitry Andric bool HasVL; 160*fe6060f1SDimitry Andric bool HasNoMaskedOverloaded; 161*fe6060f1SDimitry Andric bool HasAutoDef; // There is automiatic definition in header 162*fe6060f1SDimitry Andric std::string ManualCodegen; 163*fe6060f1SDimitry Andric RVVTypePtr OutputType; // Builtin output type 164*fe6060f1SDimitry Andric RVVTypes InputTypes; // Builtin input types 165*fe6060f1SDimitry Andric // The types we use to obtain the specific LLVM intrinsic. They are index of 166*fe6060f1SDimitry Andric // InputTypes. -1 means the return type. 167*fe6060f1SDimitry Andric std::vector<int64_t> IntrinsicTypes; 168*fe6060f1SDimitry Andric uint8_t RISCVExtensions = 0; 169*fe6060f1SDimitry Andric unsigned NF = 1; 170*fe6060f1SDimitry Andric 171*fe6060f1SDimitry Andric public: 172*fe6060f1SDimitry Andric RVVIntrinsic(StringRef Name, StringRef Suffix, StringRef MangledName, 173*fe6060f1SDimitry Andric StringRef MangledSuffix, StringRef IRName, bool HasSideEffects, 174*fe6060f1SDimitry Andric bool IsMask, bool HasMaskedOffOperand, bool HasVL, 175*fe6060f1SDimitry Andric bool HasNoMaskedOverloaded, bool HasAutoDef, 176*fe6060f1SDimitry Andric StringRef ManualCodegen, const RVVTypes &Types, 177*fe6060f1SDimitry Andric const std::vector<int64_t> &IntrinsicTypes, 178*fe6060f1SDimitry Andric StringRef RequiredExtension, unsigned NF); 179*fe6060f1SDimitry Andric ~RVVIntrinsic() = default; 180*fe6060f1SDimitry Andric 181*fe6060f1SDimitry Andric StringRef getName() const { return Name; } 182*fe6060f1SDimitry Andric StringRef getMangledName() const { return MangledName; } 183*fe6060f1SDimitry Andric bool hasSideEffects() const { return HasSideEffects; } 184*fe6060f1SDimitry Andric bool hasMaskedOffOperand() const { return HasMaskedOffOperand; } 185*fe6060f1SDimitry Andric bool hasVL() const { return HasVL; } 186*fe6060f1SDimitry Andric bool hasNoMaskedOverloaded() const { return HasNoMaskedOverloaded; } 187*fe6060f1SDimitry Andric bool hasManualCodegen() const { return !ManualCodegen.empty(); } 188*fe6060f1SDimitry Andric bool hasAutoDef() const { return HasAutoDef; } 189*fe6060f1SDimitry Andric bool isMask() const { return IsMask; } 190*fe6060f1SDimitry Andric StringRef getIRName() const { return IRName; } 191*fe6060f1SDimitry Andric StringRef getManualCodegen() const { return ManualCodegen; } 192*fe6060f1SDimitry Andric uint8_t getRISCVExtensions() const { return RISCVExtensions; } 193*fe6060f1SDimitry Andric unsigned getNF() const { return NF; } 194*fe6060f1SDimitry Andric 195*fe6060f1SDimitry Andric // Return the type string for a BUILTIN() macro in Builtins.def. 196*fe6060f1SDimitry Andric std::string getBuiltinTypeStr() const; 197*fe6060f1SDimitry Andric 198*fe6060f1SDimitry Andric // Emit the code block for switch body in EmitRISCVBuiltinExpr, it should 199*fe6060f1SDimitry Andric // init the RVVIntrinsic ID and IntrinsicTypes. 200*fe6060f1SDimitry Andric void emitCodeGenSwitchBody(raw_ostream &o) const; 201*fe6060f1SDimitry Andric 202*fe6060f1SDimitry Andric // Emit the macros for mapping C/C++ intrinsic function to builtin functions. 203*fe6060f1SDimitry Andric void emitIntrinsicMacro(raw_ostream &o) const; 204*fe6060f1SDimitry Andric 205*fe6060f1SDimitry Andric // Emit the mangled function definition. 206*fe6060f1SDimitry Andric void emitMangledFuncDef(raw_ostream &o) const; 207*fe6060f1SDimitry Andric }; 208*fe6060f1SDimitry Andric 209*fe6060f1SDimitry Andric class RVVEmitter { 210*fe6060f1SDimitry Andric private: 211*fe6060f1SDimitry Andric RecordKeeper &Records; 212*fe6060f1SDimitry Andric std::string HeaderCode; 213*fe6060f1SDimitry Andric // Concat BasicType, LMUL and Proto as key 214*fe6060f1SDimitry Andric StringMap<RVVType> LegalTypes; 215*fe6060f1SDimitry Andric StringSet<> IllegalTypes; 216*fe6060f1SDimitry Andric 217*fe6060f1SDimitry Andric public: 218*fe6060f1SDimitry Andric RVVEmitter(RecordKeeper &R) : Records(R) {} 219*fe6060f1SDimitry Andric 220*fe6060f1SDimitry Andric /// Emit riscv_vector.h 221*fe6060f1SDimitry Andric void createHeader(raw_ostream &o); 222*fe6060f1SDimitry Andric 223*fe6060f1SDimitry Andric /// Emit all the __builtin prototypes and code needed by Sema. 224*fe6060f1SDimitry Andric void createBuiltins(raw_ostream &o); 225*fe6060f1SDimitry Andric 226*fe6060f1SDimitry Andric /// Emit all the information needed to map builtin -> LLVM IR intrinsic. 227*fe6060f1SDimitry Andric void createCodeGen(raw_ostream &o); 228*fe6060f1SDimitry Andric 229*fe6060f1SDimitry Andric std::string getSuffixStr(char Type, int Log2LMUL, StringRef Prototypes); 230*fe6060f1SDimitry Andric 231*fe6060f1SDimitry Andric private: 232*fe6060f1SDimitry Andric /// Create all intrinsics and add them to \p Out 233*fe6060f1SDimitry Andric void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out); 234*fe6060f1SDimitry Andric /// Compute output and input types by applying different config (basic type 235*fe6060f1SDimitry Andric /// and LMUL with type transformers). It also record result of type in legal 236*fe6060f1SDimitry Andric /// or illegal set to avoid compute the same config again. The result maybe 237*fe6060f1SDimitry Andric /// have illegal RVVType. 238*fe6060f1SDimitry Andric Optional<RVVTypes> computeTypes(BasicType BT, int Log2LMUL, unsigned NF, 239*fe6060f1SDimitry Andric ArrayRef<std::string> PrototypeSeq); 240*fe6060f1SDimitry Andric Optional<RVVTypePtr> computeType(BasicType BT, int Log2LMUL, StringRef Proto); 241*fe6060f1SDimitry Andric 242*fe6060f1SDimitry Andric /// Emit Acrh predecessor definitions and body, assume the element of Defs are 243*fe6060f1SDimitry Andric /// sorted by extension. 244*fe6060f1SDimitry Andric void emitArchMacroAndBody( 245*fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &o, 246*fe6060f1SDimitry Andric std::function<void(raw_ostream &, const RVVIntrinsic &)>); 247*fe6060f1SDimitry Andric 248*fe6060f1SDimitry Andric // Emit the architecture preprocessor definitions. Return true when emits 249*fe6060f1SDimitry Andric // non-empty string. 250*fe6060f1SDimitry Andric bool emitExtDefStr(uint8_t Extensions, raw_ostream &o); 251*fe6060f1SDimitry Andric // Slice Prototypes string into sub prototype string and process each sub 252*fe6060f1SDimitry Andric // prototype string individually in the Handler. 253*fe6060f1SDimitry Andric void parsePrototypes(StringRef Prototypes, 254*fe6060f1SDimitry Andric std::function<void(StringRef)> Handler); 255*fe6060f1SDimitry Andric }; 256*fe6060f1SDimitry Andric 257*fe6060f1SDimitry Andric } // namespace 258*fe6060f1SDimitry Andric 259*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 260*fe6060f1SDimitry Andric // Type implementation 261*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 262*fe6060f1SDimitry Andric 263*fe6060f1SDimitry Andric LMULType::LMULType(int NewLog2LMUL) { 264*fe6060f1SDimitry Andric // Check Log2LMUL is -3, -2, -1, 0, 1, 2, 3 265*fe6060f1SDimitry Andric assert(NewLog2LMUL <= 3 && NewLog2LMUL >= -3 && "Bad LMUL number!"); 266*fe6060f1SDimitry Andric Log2LMUL = NewLog2LMUL; 267*fe6060f1SDimitry Andric } 268*fe6060f1SDimitry Andric 269*fe6060f1SDimitry Andric std::string LMULType::str() const { 270*fe6060f1SDimitry Andric if (Log2LMUL < 0) 271*fe6060f1SDimitry Andric return "mf" + utostr(1ULL << (-Log2LMUL)); 272*fe6060f1SDimitry Andric return "m" + utostr(1ULL << Log2LMUL); 273*fe6060f1SDimitry Andric } 274*fe6060f1SDimitry Andric 275*fe6060f1SDimitry Andric VScaleVal LMULType::getScale(unsigned ElementBitwidth) const { 276*fe6060f1SDimitry Andric int Log2ScaleResult = 0; 277*fe6060f1SDimitry Andric switch (ElementBitwidth) { 278*fe6060f1SDimitry Andric default: 279*fe6060f1SDimitry Andric break; 280*fe6060f1SDimitry Andric case 8: 281*fe6060f1SDimitry Andric Log2ScaleResult = Log2LMUL + 3; 282*fe6060f1SDimitry Andric break; 283*fe6060f1SDimitry Andric case 16: 284*fe6060f1SDimitry Andric Log2ScaleResult = Log2LMUL + 2; 285*fe6060f1SDimitry Andric break; 286*fe6060f1SDimitry Andric case 32: 287*fe6060f1SDimitry Andric Log2ScaleResult = Log2LMUL + 1; 288*fe6060f1SDimitry Andric break; 289*fe6060f1SDimitry Andric case 64: 290*fe6060f1SDimitry Andric Log2ScaleResult = Log2LMUL; 291*fe6060f1SDimitry Andric break; 292*fe6060f1SDimitry Andric } 293*fe6060f1SDimitry Andric // Illegal vscale result would be less than 1 294*fe6060f1SDimitry Andric if (Log2ScaleResult < 0) 295*fe6060f1SDimitry Andric return None; 296*fe6060f1SDimitry Andric return 1 << Log2ScaleResult; 297*fe6060f1SDimitry Andric } 298*fe6060f1SDimitry Andric 299*fe6060f1SDimitry Andric void LMULType::MulLog2LMUL(int log2LMUL) { Log2LMUL += log2LMUL; } 300*fe6060f1SDimitry Andric 301*fe6060f1SDimitry Andric LMULType &LMULType::operator*=(uint32_t RHS) { 302*fe6060f1SDimitry Andric assert(isPowerOf2_32(RHS)); 303*fe6060f1SDimitry Andric this->Log2LMUL = this->Log2LMUL + Log2_32(RHS); 304*fe6060f1SDimitry Andric return *this; 305*fe6060f1SDimitry Andric } 306*fe6060f1SDimitry Andric 307*fe6060f1SDimitry Andric RVVType::RVVType(BasicType BT, int Log2LMUL, StringRef prototype) 308*fe6060f1SDimitry Andric : BT(BT), LMUL(LMULType(Log2LMUL)) { 309*fe6060f1SDimitry Andric applyBasicType(); 310*fe6060f1SDimitry Andric applyModifier(prototype); 311*fe6060f1SDimitry Andric Valid = verifyType(); 312*fe6060f1SDimitry Andric if (Valid) { 313*fe6060f1SDimitry Andric initBuiltinStr(); 314*fe6060f1SDimitry Andric initTypeStr(); 315*fe6060f1SDimitry Andric if (isVector()) { 316*fe6060f1SDimitry Andric initClangBuiltinStr(); 317*fe6060f1SDimitry Andric } 318*fe6060f1SDimitry Andric } 319*fe6060f1SDimitry Andric } 320*fe6060f1SDimitry Andric 321*fe6060f1SDimitry Andric // clang-format off 322*fe6060f1SDimitry Andric // boolean type are encoded the ratio of n (SEW/LMUL) 323*fe6060f1SDimitry Andric // SEW/LMUL | 1 | 2 | 4 | 8 | 16 | 32 | 64 324*fe6060f1SDimitry Andric // c type | vbool64_t | vbool32_t | vbool16_t | vbool8_t | vbool4_t | vbool2_t | vbool1_t 325*fe6060f1SDimitry Andric // IR type | nxv1i1 | nxv2i1 | nxv4i1 | nxv8i1 | nxv16i1 | nxv32i1 | nxv64i1 326*fe6060f1SDimitry Andric 327*fe6060f1SDimitry Andric // type\lmul | 1/8 | 1/4 | 1/2 | 1 | 2 | 4 | 8 328*fe6060f1SDimitry Andric // -------- |------ | -------- | ------- | ------- | -------- | -------- | -------- 329*fe6060f1SDimitry Andric // i64 | N/A | N/A | N/A | nxv1i64 | nxv2i64 | nxv4i64 | nxv8i64 330*fe6060f1SDimitry Andric // i32 | N/A | N/A | nxv1i32 | nxv2i32 | nxv4i32 | nxv8i32 | nxv16i32 331*fe6060f1SDimitry Andric // i16 | N/A | nxv1i16 | nxv2i16 | nxv4i16 | nxv8i16 | nxv16i16 | nxv32i16 332*fe6060f1SDimitry Andric // i8 | nxv1i8 | nxv2i8 | nxv4i8 | nxv8i8 | nxv16i8 | nxv32i8 | nxv64i8 333*fe6060f1SDimitry Andric // double | N/A | N/A | N/A | nxv1f64 | nxv2f64 | nxv4f64 | nxv8f64 334*fe6060f1SDimitry Andric // float | N/A | N/A | nxv1f32 | nxv2f32 | nxv4f32 | nxv8f32 | nxv16f32 335*fe6060f1SDimitry Andric // half | N/A | nxv1f16 | nxv2f16 | nxv4f16 | nxv8f16 | nxv16f16 | nxv32f16 336*fe6060f1SDimitry Andric // clang-format on 337*fe6060f1SDimitry Andric 338*fe6060f1SDimitry Andric bool RVVType::verifyType() const { 339*fe6060f1SDimitry Andric if (ScalarType == Invalid) 340*fe6060f1SDimitry Andric return false; 341*fe6060f1SDimitry Andric if (isScalar()) 342*fe6060f1SDimitry Andric return true; 343*fe6060f1SDimitry Andric if (!Scale.hasValue()) 344*fe6060f1SDimitry Andric return false; 345*fe6060f1SDimitry Andric if (isFloat() && ElementBitwidth == 8) 346*fe6060f1SDimitry Andric return false; 347*fe6060f1SDimitry Andric unsigned V = Scale.getValue(); 348*fe6060f1SDimitry Andric switch (ElementBitwidth) { 349*fe6060f1SDimitry Andric case 1: 350*fe6060f1SDimitry Andric case 8: 351*fe6060f1SDimitry Andric // Check Scale is 1,2,4,8,16,32,64 352*fe6060f1SDimitry Andric return (V <= 64 && isPowerOf2_32(V)); 353*fe6060f1SDimitry Andric case 16: 354*fe6060f1SDimitry Andric // Check Scale is 1,2,4,8,16,32 355*fe6060f1SDimitry Andric return (V <= 32 && isPowerOf2_32(V)); 356*fe6060f1SDimitry Andric case 32: 357*fe6060f1SDimitry Andric // Check Scale is 1,2,4,8,16 358*fe6060f1SDimitry Andric return (V <= 16 && isPowerOf2_32(V)); 359*fe6060f1SDimitry Andric case 64: 360*fe6060f1SDimitry Andric // Check Scale is 1,2,4,8 361*fe6060f1SDimitry Andric return (V <= 8 && isPowerOf2_32(V)); 362*fe6060f1SDimitry Andric } 363*fe6060f1SDimitry Andric return false; 364*fe6060f1SDimitry Andric } 365*fe6060f1SDimitry Andric 366*fe6060f1SDimitry Andric void RVVType::initBuiltinStr() { 367*fe6060f1SDimitry Andric assert(isValid() && "RVVType is invalid"); 368*fe6060f1SDimitry Andric switch (ScalarType) { 369*fe6060f1SDimitry Andric case ScalarTypeKind::Void: 370*fe6060f1SDimitry Andric BuiltinStr = "v"; 371*fe6060f1SDimitry Andric return; 372*fe6060f1SDimitry Andric case ScalarTypeKind::Size_t: 373*fe6060f1SDimitry Andric BuiltinStr = "z"; 374*fe6060f1SDimitry Andric if (IsImmediate) 375*fe6060f1SDimitry Andric BuiltinStr = "I" + BuiltinStr; 376*fe6060f1SDimitry Andric if (IsPointer) 377*fe6060f1SDimitry Andric BuiltinStr += "*"; 378*fe6060f1SDimitry Andric return; 379*fe6060f1SDimitry Andric case ScalarTypeKind::Ptrdiff_t: 380*fe6060f1SDimitry Andric BuiltinStr = "Y"; 381*fe6060f1SDimitry Andric return; 382*fe6060f1SDimitry Andric case ScalarTypeKind::UnsignedLong: 383*fe6060f1SDimitry Andric BuiltinStr = "ULi"; 384*fe6060f1SDimitry Andric return; 385*fe6060f1SDimitry Andric case ScalarTypeKind::SignedLong: 386*fe6060f1SDimitry Andric BuiltinStr = "Li"; 387*fe6060f1SDimitry Andric return; 388*fe6060f1SDimitry Andric case ScalarTypeKind::Boolean: 389*fe6060f1SDimitry Andric assert(ElementBitwidth == 1); 390*fe6060f1SDimitry Andric BuiltinStr += "b"; 391*fe6060f1SDimitry Andric break; 392*fe6060f1SDimitry Andric case ScalarTypeKind::SignedInteger: 393*fe6060f1SDimitry Andric case ScalarTypeKind::UnsignedInteger: 394*fe6060f1SDimitry Andric switch (ElementBitwidth) { 395*fe6060f1SDimitry Andric case 8: 396*fe6060f1SDimitry Andric BuiltinStr += "c"; 397*fe6060f1SDimitry Andric break; 398*fe6060f1SDimitry Andric case 16: 399*fe6060f1SDimitry Andric BuiltinStr += "s"; 400*fe6060f1SDimitry Andric break; 401*fe6060f1SDimitry Andric case 32: 402*fe6060f1SDimitry Andric BuiltinStr += "i"; 403*fe6060f1SDimitry Andric break; 404*fe6060f1SDimitry Andric case 64: 405*fe6060f1SDimitry Andric BuiltinStr += "Wi"; 406*fe6060f1SDimitry Andric break; 407*fe6060f1SDimitry Andric default: 408*fe6060f1SDimitry Andric llvm_unreachable("Unhandled ElementBitwidth!"); 409*fe6060f1SDimitry Andric } 410*fe6060f1SDimitry Andric if (isSignedInteger()) 411*fe6060f1SDimitry Andric BuiltinStr = "S" + BuiltinStr; 412*fe6060f1SDimitry Andric else 413*fe6060f1SDimitry Andric BuiltinStr = "U" + BuiltinStr; 414*fe6060f1SDimitry Andric break; 415*fe6060f1SDimitry Andric case ScalarTypeKind::Float: 416*fe6060f1SDimitry Andric switch (ElementBitwidth) { 417*fe6060f1SDimitry Andric case 16: 418*fe6060f1SDimitry Andric BuiltinStr += "x"; 419*fe6060f1SDimitry Andric break; 420*fe6060f1SDimitry Andric case 32: 421*fe6060f1SDimitry Andric BuiltinStr += "f"; 422*fe6060f1SDimitry Andric break; 423*fe6060f1SDimitry Andric case 64: 424*fe6060f1SDimitry Andric BuiltinStr += "d"; 425*fe6060f1SDimitry Andric break; 426*fe6060f1SDimitry Andric default: 427*fe6060f1SDimitry Andric llvm_unreachable("Unhandled ElementBitwidth!"); 428*fe6060f1SDimitry Andric } 429*fe6060f1SDimitry Andric break; 430*fe6060f1SDimitry Andric default: 431*fe6060f1SDimitry Andric llvm_unreachable("ScalarType is invalid!"); 432*fe6060f1SDimitry Andric } 433*fe6060f1SDimitry Andric if (IsImmediate) 434*fe6060f1SDimitry Andric BuiltinStr = "I" + BuiltinStr; 435*fe6060f1SDimitry Andric if (isScalar()) { 436*fe6060f1SDimitry Andric if (IsConstant) 437*fe6060f1SDimitry Andric BuiltinStr += "C"; 438*fe6060f1SDimitry Andric if (IsPointer) 439*fe6060f1SDimitry Andric BuiltinStr += "*"; 440*fe6060f1SDimitry Andric return; 441*fe6060f1SDimitry Andric } 442*fe6060f1SDimitry Andric BuiltinStr = "q" + utostr(Scale.getValue()) + BuiltinStr; 443*fe6060f1SDimitry Andric // Pointer to vector types. Defined for Zvlsseg load intrinsics. 444*fe6060f1SDimitry Andric // Zvlsseg load intrinsics have pointer type arguments to store the loaded 445*fe6060f1SDimitry Andric // vector values. 446*fe6060f1SDimitry Andric if (IsPointer) 447*fe6060f1SDimitry Andric BuiltinStr += "*"; 448*fe6060f1SDimitry Andric } 449*fe6060f1SDimitry Andric 450*fe6060f1SDimitry Andric void RVVType::initClangBuiltinStr() { 451*fe6060f1SDimitry Andric assert(isValid() && "RVVType is invalid"); 452*fe6060f1SDimitry Andric assert(isVector() && "Handle Vector type only"); 453*fe6060f1SDimitry Andric 454*fe6060f1SDimitry Andric ClangBuiltinStr = "__rvv_"; 455*fe6060f1SDimitry Andric switch (ScalarType) { 456*fe6060f1SDimitry Andric case ScalarTypeKind::Boolean: 457*fe6060f1SDimitry Andric ClangBuiltinStr += "bool" + utostr(64 / Scale.getValue()) + "_t"; 458*fe6060f1SDimitry Andric return; 459*fe6060f1SDimitry Andric case ScalarTypeKind::Float: 460*fe6060f1SDimitry Andric ClangBuiltinStr += "float"; 461*fe6060f1SDimitry Andric break; 462*fe6060f1SDimitry Andric case ScalarTypeKind::SignedInteger: 463*fe6060f1SDimitry Andric ClangBuiltinStr += "int"; 464*fe6060f1SDimitry Andric break; 465*fe6060f1SDimitry Andric case ScalarTypeKind::UnsignedInteger: 466*fe6060f1SDimitry Andric ClangBuiltinStr += "uint"; 467*fe6060f1SDimitry Andric break; 468*fe6060f1SDimitry Andric default: 469*fe6060f1SDimitry Andric llvm_unreachable("ScalarTypeKind is invalid"); 470*fe6060f1SDimitry Andric } 471*fe6060f1SDimitry Andric ClangBuiltinStr += utostr(ElementBitwidth) + LMUL.str() + "_t"; 472*fe6060f1SDimitry Andric } 473*fe6060f1SDimitry Andric 474*fe6060f1SDimitry Andric void RVVType::initTypeStr() { 475*fe6060f1SDimitry Andric assert(isValid() && "RVVType is invalid"); 476*fe6060f1SDimitry Andric 477*fe6060f1SDimitry Andric if (IsConstant) 478*fe6060f1SDimitry Andric Str += "const "; 479*fe6060f1SDimitry Andric 480*fe6060f1SDimitry Andric auto getTypeString = [&](StringRef TypeStr) { 481*fe6060f1SDimitry Andric if (isScalar()) 482*fe6060f1SDimitry Andric return Twine(TypeStr + Twine(ElementBitwidth) + "_t").str(); 483*fe6060f1SDimitry Andric return Twine("v" + TypeStr + Twine(ElementBitwidth) + LMUL.str() + "_t") 484*fe6060f1SDimitry Andric .str(); 485*fe6060f1SDimitry Andric }; 486*fe6060f1SDimitry Andric 487*fe6060f1SDimitry Andric switch (ScalarType) { 488*fe6060f1SDimitry Andric case ScalarTypeKind::Void: 489*fe6060f1SDimitry Andric Str = "void"; 490*fe6060f1SDimitry Andric return; 491*fe6060f1SDimitry Andric case ScalarTypeKind::Size_t: 492*fe6060f1SDimitry Andric Str = "size_t"; 493*fe6060f1SDimitry Andric if (IsPointer) 494*fe6060f1SDimitry Andric Str += " *"; 495*fe6060f1SDimitry Andric return; 496*fe6060f1SDimitry Andric case ScalarTypeKind::Ptrdiff_t: 497*fe6060f1SDimitry Andric Str = "ptrdiff_t"; 498*fe6060f1SDimitry Andric return; 499*fe6060f1SDimitry Andric case ScalarTypeKind::UnsignedLong: 500*fe6060f1SDimitry Andric Str = "unsigned long"; 501*fe6060f1SDimitry Andric return; 502*fe6060f1SDimitry Andric case ScalarTypeKind::SignedLong: 503*fe6060f1SDimitry Andric Str = "long"; 504*fe6060f1SDimitry Andric return; 505*fe6060f1SDimitry Andric case ScalarTypeKind::Boolean: 506*fe6060f1SDimitry Andric if (isScalar()) 507*fe6060f1SDimitry Andric Str += "bool"; 508*fe6060f1SDimitry Andric else 509*fe6060f1SDimitry Andric // Vector bool is special case, the formulate is 510*fe6060f1SDimitry Andric // `vbool<N>_t = MVT::nxv<64/N>i1` ex. vbool16_t = MVT::4i1 511*fe6060f1SDimitry Andric Str += "vbool" + utostr(64 / Scale.getValue()) + "_t"; 512*fe6060f1SDimitry Andric break; 513*fe6060f1SDimitry Andric case ScalarTypeKind::Float: 514*fe6060f1SDimitry Andric if (isScalar()) { 515*fe6060f1SDimitry Andric if (ElementBitwidth == 64) 516*fe6060f1SDimitry Andric Str += "double"; 517*fe6060f1SDimitry Andric else if (ElementBitwidth == 32) 518*fe6060f1SDimitry Andric Str += "float"; 519*fe6060f1SDimitry Andric else if (ElementBitwidth == 16) 520*fe6060f1SDimitry Andric Str += "_Float16"; 521*fe6060f1SDimitry Andric else 522*fe6060f1SDimitry Andric llvm_unreachable("Unhandled floating type."); 523*fe6060f1SDimitry Andric } else 524*fe6060f1SDimitry Andric Str += getTypeString("float"); 525*fe6060f1SDimitry Andric break; 526*fe6060f1SDimitry Andric case ScalarTypeKind::SignedInteger: 527*fe6060f1SDimitry Andric Str += getTypeString("int"); 528*fe6060f1SDimitry Andric break; 529*fe6060f1SDimitry Andric case ScalarTypeKind::UnsignedInteger: 530*fe6060f1SDimitry Andric Str += getTypeString("uint"); 531*fe6060f1SDimitry Andric break; 532*fe6060f1SDimitry Andric default: 533*fe6060f1SDimitry Andric llvm_unreachable("ScalarType is invalid!"); 534*fe6060f1SDimitry Andric } 535*fe6060f1SDimitry Andric if (IsPointer) 536*fe6060f1SDimitry Andric Str += " *"; 537*fe6060f1SDimitry Andric } 538*fe6060f1SDimitry Andric 539*fe6060f1SDimitry Andric void RVVType::initShortStr() { 540*fe6060f1SDimitry Andric switch (ScalarType) { 541*fe6060f1SDimitry Andric case ScalarTypeKind::Boolean: 542*fe6060f1SDimitry Andric assert(isVector()); 543*fe6060f1SDimitry Andric ShortStr = "b" + utostr(64 / Scale.getValue()); 544*fe6060f1SDimitry Andric return; 545*fe6060f1SDimitry Andric case ScalarTypeKind::Float: 546*fe6060f1SDimitry Andric ShortStr = "f" + utostr(ElementBitwidth); 547*fe6060f1SDimitry Andric break; 548*fe6060f1SDimitry Andric case ScalarTypeKind::SignedInteger: 549*fe6060f1SDimitry Andric ShortStr = "i" + utostr(ElementBitwidth); 550*fe6060f1SDimitry Andric break; 551*fe6060f1SDimitry Andric case ScalarTypeKind::UnsignedInteger: 552*fe6060f1SDimitry Andric ShortStr = "u" + utostr(ElementBitwidth); 553*fe6060f1SDimitry Andric break; 554*fe6060f1SDimitry Andric default: 555*fe6060f1SDimitry Andric PrintFatalError("Unhandled case!"); 556*fe6060f1SDimitry Andric } 557*fe6060f1SDimitry Andric if (isVector()) 558*fe6060f1SDimitry Andric ShortStr += LMUL.str(); 559*fe6060f1SDimitry Andric } 560*fe6060f1SDimitry Andric 561*fe6060f1SDimitry Andric void RVVType::applyBasicType() { 562*fe6060f1SDimitry Andric switch (BT) { 563*fe6060f1SDimitry Andric case 'c': 564*fe6060f1SDimitry Andric ElementBitwidth = 8; 565*fe6060f1SDimitry Andric ScalarType = ScalarTypeKind::SignedInteger; 566*fe6060f1SDimitry Andric break; 567*fe6060f1SDimitry Andric case 's': 568*fe6060f1SDimitry Andric ElementBitwidth = 16; 569*fe6060f1SDimitry Andric ScalarType = ScalarTypeKind::SignedInteger; 570*fe6060f1SDimitry Andric break; 571*fe6060f1SDimitry Andric case 'i': 572*fe6060f1SDimitry Andric ElementBitwidth = 32; 573*fe6060f1SDimitry Andric ScalarType = ScalarTypeKind::SignedInteger; 574*fe6060f1SDimitry Andric break; 575*fe6060f1SDimitry Andric case 'l': 576*fe6060f1SDimitry Andric ElementBitwidth = 64; 577*fe6060f1SDimitry Andric ScalarType = ScalarTypeKind::SignedInteger; 578*fe6060f1SDimitry Andric break; 579*fe6060f1SDimitry Andric case 'x': 580*fe6060f1SDimitry Andric ElementBitwidth = 16; 581*fe6060f1SDimitry Andric ScalarType = ScalarTypeKind::Float; 582*fe6060f1SDimitry Andric break; 583*fe6060f1SDimitry Andric case 'f': 584*fe6060f1SDimitry Andric ElementBitwidth = 32; 585*fe6060f1SDimitry Andric ScalarType = ScalarTypeKind::Float; 586*fe6060f1SDimitry Andric break; 587*fe6060f1SDimitry Andric case 'd': 588*fe6060f1SDimitry Andric ElementBitwidth = 64; 589*fe6060f1SDimitry Andric ScalarType = ScalarTypeKind::Float; 590*fe6060f1SDimitry Andric break; 591*fe6060f1SDimitry Andric default: 592*fe6060f1SDimitry Andric PrintFatalError("Unhandled type code!"); 593*fe6060f1SDimitry Andric } 594*fe6060f1SDimitry Andric assert(ElementBitwidth != 0 && "Bad element bitwidth!"); 595*fe6060f1SDimitry Andric } 596*fe6060f1SDimitry Andric 597*fe6060f1SDimitry Andric void RVVType::applyModifier(StringRef Transformer) { 598*fe6060f1SDimitry Andric if (Transformer.empty()) 599*fe6060f1SDimitry Andric return; 600*fe6060f1SDimitry Andric // Handle primitive type transformer 601*fe6060f1SDimitry Andric auto PType = Transformer.back(); 602*fe6060f1SDimitry Andric switch (PType) { 603*fe6060f1SDimitry Andric case 'e': 604*fe6060f1SDimitry Andric Scale = 0; 605*fe6060f1SDimitry Andric break; 606*fe6060f1SDimitry Andric case 'v': 607*fe6060f1SDimitry Andric Scale = LMUL.getScale(ElementBitwidth); 608*fe6060f1SDimitry Andric break; 609*fe6060f1SDimitry Andric case 'w': 610*fe6060f1SDimitry Andric ElementBitwidth *= 2; 611*fe6060f1SDimitry Andric LMUL *= 2; 612*fe6060f1SDimitry Andric Scale = LMUL.getScale(ElementBitwidth); 613*fe6060f1SDimitry Andric break; 614*fe6060f1SDimitry Andric case 'q': 615*fe6060f1SDimitry Andric ElementBitwidth *= 4; 616*fe6060f1SDimitry Andric LMUL *= 4; 617*fe6060f1SDimitry Andric Scale = LMUL.getScale(ElementBitwidth); 618*fe6060f1SDimitry Andric break; 619*fe6060f1SDimitry Andric case 'o': 620*fe6060f1SDimitry Andric ElementBitwidth *= 8; 621*fe6060f1SDimitry Andric LMUL *= 8; 622*fe6060f1SDimitry Andric Scale = LMUL.getScale(ElementBitwidth); 623*fe6060f1SDimitry Andric break; 624*fe6060f1SDimitry Andric case 'm': 625*fe6060f1SDimitry Andric ScalarType = ScalarTypeKind::Boolean; 626*fe6060f1SDimitry Andric Scale = LMUL.getScale(ElementBitwidth); 627*fe6060f1SDimitry Andric ElementBitwidth = 1; 628*fe6060f1SDimitry Andric break; 629*fe6060f1SDimitry Andric case '0': 630*fe6060f1SDimitry Andric ScalarType = ScalarTypeKind::Void; 631*fe6060f1SDimitry Andric break; 632*fe6060f1SDimitry Andric case 'z': 633*fe6060f1SDimitry Andric ScalarType = ScalarTypeKind::Size_t; 634*fe6060f1SDimitry Andric break; 635*fe6060f1SDimitry Andric case 't': 636*fe6060f1SDimitry Andric ScalarType = ScalarTypeKind::Ptrdiff_t; 637*fe6060f1SDimitry Andric break; 638*fe6060f1SDimitry Andric case 'u': 639*fe6060f1SDimitry Andric ScalarType = ScalarTypeKind::UnsignedLong; 640*fe6060f1SDimitry Andric break; 641*fe6060f1SDimitry Andric case 'l': 642*fe6060f1SDimitry Andric ScalarType = ScalarTypeKind::SignedLong; 643*fe6060f1SDimitry Andric break; 644*fe6060f1SDimitry Andric default: 645*fe6060f1SDimitry Andric PrintFatalError("Illegal primitive type transformers!"); 646*fe6060f1SDimitry Andric } 647*fe6060f1SDimitry Andric Transformer = Transformer.drop_back(); 648*fe6060f1SDimitry Andric 649*fe6060f1SDimitry Andric // Extract and compute complex type transformer. It can only appear one time. 650*fe6060f1SDimitry Andric if (Transformer.startswith("(")) { 651*fe6060f1SDimitry Andric size_t Idx = Transformer.find(')'); 652*fe6060f1SDimitry Andric assert(Idx != StringRef::npos); 653*fe6060f1SDimitry Andric StringRef ComplexType = Transformer.slice(1, Idx); 654*fe6060f1SDimitry Andric Transformer = Transformer.drop_front(Idx + 1); 655*fe6060f1SDimitry Andric assert(Transformer.find('(') == StringRef::npos && 656*fe6060f1SDimitry Andric "Only allow one complex type transformer"); 657*fe6060f1SDimitry Andric 658*fe6060f1SDimitry Andric auto UpdateAndCheckComplexProto = [&]() { 659*fe6060f1SDimitry Andric Scale = LMUL.getScale(ElementBitwidth); 660*fe6060f1SDimitry Andric const StringRef VectorPrototypes("vwqom"); 661*fe6060f1SDimitry Andric if (!VectorPrototypes.contains(PType)) 662*fe6060f1SDimitry Andric PrintFatalError("Complex type transformer only supports vector type!"); 663*fe6060f1SDimitry Andric if (Transformer.find_first_of("PCKWS") != StringRef::npos) 664*fe6060f1SDimitry Andric PrintFatalError( 665*fe6060f1SDimitry Andric "Illegal type transformer for Complex type transformer"); 666*fe6060f1SDimitry Andric }; 667*fe6060f1SDimitry Andric auto ComputeFixedLog2LMUL = 668*fe6060f1SDimitry Andric [&](StringRef Value, 669*fe6060f1SDimitry Andric std::function<bool(const int32_t &, const int32_t &)> Compare) { 670*fe6060f1SDimitry Andric int32_t Log2LMUL; 671*fe6060f1SDimitry Andric Value.getAsInteger(10, Log2LMUL); 672*fe6060f1SDimitry Andric if (!Compare(Log2LMUL, LMUL.Log2LMUL)) { 673*fe6060f1SDimitry Andric ScalarType = Invalid; 674*fe6060f1SDimitry Andric return false; 675*fe6060f1SDimitry Andric } 676*fe6060f1SDimitry Andric // Update new LMUL 677*fe6060f1SDimitry Andric LMUL = LMULType(Log2LMUL); 678*fe6060f1SDimitry Andric UpdateAndCheckComplexProto(); 679*fe6060f1SDimitry Andric return true; 680*fe6060f1SDimitry Andric }; 681*fe6060f1SDimitry Andric auto ComplexTT = ComplexType.split(":"); 682*fe6060f1SDimitry Andric if (ComplexTT.first == "Log2EEW") { 683*fe6060f1SDimitry Andric uint32_t Log2EEW; 684*fe6060f1SDimitry Andric ComplexTT.second.getAsInteger(10, Log2EEW); 685*fe6060f1SDimitry Andric // update new elmul = (eew/sew) * lmul 686*fe6060f1SDimitry Andric LMUL.MulLog2LMUL(Log2EEW - Log2_32(ElementBitwidth)); 687*fe6060f1SDimitry Andric // update new eew 688*fe6060f1SDimitry Andric ElementBitwidth = 1 << Log2EEW; 689*fe6060f1SDimitry Andric ScalarType = ScalarTypeKind::SignedInteger; 690*fe6060f1SDimitry Andric UpdateAndCheckComplexProto(); 691*fe6060f1SDimitry Andric } else if (ComplexTT.first == "FixedSEW") { 692*fe6060f1SDimitry Andric uint32_t NewSEW; 693*fe6060f1SDimitry Andric ComplexTT.second.getAsInteger(10, NewSEW); 694*fe6060f1SDimitry Andric // Set invalid type if src and dst SEW are same. 695*fe6060f1SDimitry Andric if (ElementBitwidth == NewSEW) { 696*fe6060f1SDimitry Andric ScalarType = Invalid; 697*fe6060f1SDimitry Andric return; 698*fe6060f1SDimitry Andric } 699*fe6060f1SDimitry Andric // Update new SEW 700*fe6060f1SDimitry Andric ElementBitwidth = NewSEW; 701*fe6060f1SDimitry Andric UpdateAndCheckComplexProto(); 702*fe6060f1SDimitry Andric } else if (ComplexTT.first == "LFixedLog2LMUL") { 703*fe6060f1SDimitry Andric // New LMUL should be larger than old 704*fe6060f1SDimitry Andric if (!ComputeFixedLog2LMUL(ComplexTT.second, std::greater<int32_t>())) 705*fe6060f1SDimitry Andric return; 706*fe6060f1SDimitry Andric } else if (ComplexTT.first == "SFixedLog2LMUL") { 707*fe6060f1SDimitry Andric // New LMUL should be smaller than old 708*fe6060f1SDimitry Andric if (!ComputeFixedLog2LMUL(ComplexTT.second, std::less<int32_t>())) 709*fe6060f1SDimitry Andric return; 710*fe6060f1SDimitry Andric } else { 711*fe6060f1SDimitry Andric PrintFatalError("Illegal complex type transformers!"); 712*fe6060f1SDimitry Andric } 713*fe6060f1SDimitry Andric } 714*fe6060f1SDimitry Andric 715*fe6060f1SDimitry Andric // Compute the remain type transformers 716*fe6060f1SDimitry Andric for (char I : Transformer) { 717*fe6060f1SDimitry Andric switch (I) { 718*fe6060f1SDimitry Andric case 'P': 719*fe6060f1SDimitry Andric if (IsConstant) 720*fe6060f1SDimitry Andric PrintFatalError("'P' transformer cannot be used after 'C'"); 721*fe6060f1SDimitry Andric if (IsPointer) 722*fe6060f1SDimitry Andric PrintFatalError("'P' transformer cannot be used twice"); 723*fe6060f1SDimitry Andric IsPointer = true; 724*fe6060f1SDimitry Andric break; 725*fe6060f1SDimitry Andric case 'C': 726*fe6060f1SDimitry Andric if (IsConstant) 727*fe6060f1SDimitry Andric PrintFatalError("'C' transformer cannot be used twice"); 728*fe6060f1SDimitry Andric IsConstant = true; 729*fe6060f1SDimitry Andric break; 730*fe6060f1SDimitry Andric case 'K': 731*fe6060f1SDimitry Andric IsImmediate = true; 732*fe6060f1SDimitry Andric break; 733*fe6060f1SDimitry Andric case 'U': 734*fe6060f1SDimitry Andric ScalarType = ScalarTypeKind::UnsignedInteger; 735*fe6060f1SDimitry Andric break; 736*fe6060f1SDimitry Andric case 'I': 737*fe6060f1SDimitry Andric ScalarType = ScalarTypeKind::SignedInteger; 738*fe6060f1SDimitry Andric break; 739*fe6060f1SDimitry Andric case 'F': 740*fe6060f1SDimitry Andric ScalarType = ScalarTypeKind::Float; 741*fe6060f1SDimitry Andric break; 742*fe6060f1SDimitry Andric case 'S': 743*fe6060f1SDimitry Andric LMUL = LMULType(0); 744*fe6060f1SDimitry Andric // Update ElementBitwidth need to update Scale too. 745*fe6060f1SDimitry Andric Scale = LMUL.getScale(ElementBitwidth); 746*fe6060f1SDimitry Andric break; 747*fe6060f1SDimitry Andric default: 748*fe6060f1SDimitry Andric PrintFatalError("Illegal non-primitive type transformer!"); 749*fe6060f1SDimitry Andric } 750*fe6060f1SDimitry Andric } 751*fe6060f1SDimitry Andric } 752*fe6060f1SDimitry Andric 753*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 754*fe6060f1SDimitry Andric // RVVIntrinsic implementation 755*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 756*fe6060f1SDimitry Andric RVVIntrinsic::RVVIntrinsic(StringRef NewName, StringRef Suffix, 757*fe6060f1SDimitry Andric StringRef NewMangledName, StringRef MangledSuffix, 758*fe6060f1SDimitry Andric StringRef IRName, bool HasSideEffects, bool IsMask, 759*fe6060f1SDimitry Andric bool HasMaskedOffOperand, bool HasVL, 760*fe6060f1SDimitry Andric bool HasNoMaskedOverloaded, bool HasAutoDef, 761*fe6060f1SDimitry Andric StringRef ManualCodegen, const RVVTypes &OutInTypes, 762*fe6060f1SDimitry Andric const std::vector<int64_t> &NewIntrinsicTypes, 763*fe6060f1SDimitry Andric StringRef RequiredExtension, unsigned NF) 764*fe6060f1SDimitry Andric : IRName(IRName), HasSideEffects(HasSideEffects), IsMask(IsMask), 765*fe6060f1SDimitry Andric HasMaskedOffOperand(HasMaskedOffOperand), HasVL(HasVL), 766*fe6060f1SDimitry Andric HasNoMaskedOverloaded(HasNoMaskedOverloaded), HasAutoDef(HasAutoDef), 767*fe6060f1SDimitry Andric ManualCodegen(ManualCodegen.str()), NF(NF) { 768*fe6060f1SDimitry Andric 769*fe6060f1SDimitry Andric // Init Name and MangledName 770*fe6060f1SDimitry Andric Name = NewName.str(); 771*fe6060f1SDimitry Andric if (NewMangledName.empty()) 772*fe6060f1SDimitry Andric MangledName = NewName.split("_").first.str(); 773*fe6060f1SDimitry Andric else 774*fe6060f1SDimitry Andric MangledName = NewMangledName.str(); 775*fe6060f1SDimitry Andric if (!Suffix.empty()) 776*fe6060f1SDimitry Andric Name += "_" + Suffix.str(); 777*fe6060f1SDimitry Andric if (!MangledSuffix.empty()) 778*fe6060f1SDimitry Andric MangledName += "_" + MangledSuffix.str(); 779*fe6060f1SDimitry Andric if (IsMask) { 780*fe6060f1SDimitry Andric Name += "_m"; 781*fe6060f1SDimitry Andric } 782*fe6060f1SDimitry Andric // Init RISC-V extensions 783*fe6060f1SDimitry Andric for (const auto &T : OutInTypes) { 784*fe6060f1SDimitry Andric if (T->isFloatVector(16) || T->isFloat(16)) 785*fe6060f1SDimitry Andric RISCVExtensions |= RISCVExtension::Zfh; 786*fe6060f1SDimitry Andric else if (T->isFloatVector(32) || T->isFloat(32)) 787*fe6060f1SDimitry Andric RISCVExtensions |= RISCVExtension::F; 788*fe6060f1SDimitry Andric else if (T->isFloatVector(64) || T->isFloat(64)) 789*fe6060f1SDimitry Andric RISCVExtensions |= RISCVExtension::D; 790*fe6060f1SDimitry Andric } 791*fe6060f1SDimitry Andric if (RequiredExtension == "Zvamo") 792*fe6060f1SDimitry Andric RISCVExtensions |= RISCVExtension::Zvamo; 793*fe6060f1SDimitry Andric if (RequiredExtension == "Zvlsseg") 794*fe6060f1SDimitry Andric RISCVExtensions |= RISCVExtension::Zvlsseg; 795*fe6060f1SDimitry Andric 796*fe6060f1SDimitry Andric // Init OutputType and InputTypes 797*fe6060f1SDimitry Andric OutputType = OutInTypes[0]; 798*fe6060f1SDimitry Andric InputTypes.assign(OutInTypes.begin() + 1, OutInTypes.end()); 799*fe6060f1SDimitry Andric 800*fe6060f1SDimitry Andric // IntrinsicTypes is nonmasked version index. Need to update it 801*fe6060f1SDimitry Andric // if there is maskedoff operand (It is always in first operand). 802*fe6060f1SDimitry Andric IntrinsicTypes = NewIntrinsicTypes; 803*fe6060f1SDimitry Andric if (IsMask && HasMaskedOffOperand) { 804*fe6060f1SDimitry Andric for (auto &I : IntrinsicTypes) { 805*fe6060f1SDimitry Andric if (I >= 0) 806*fe6060f1SDimitry Andric I += NF; 807*fe6060f1SDimitry Andric } 808*fe6060f1SDimitry Andric } 809*fe6060f1SDimitry Andric } 810*fe6060f1SDimitry Andric 811*fe6060f1SDimitry Andric std::string RVVIntrinsic::getBuiltinTypeStr() const { 812*fe6060f1SDimitry Andric std::string S; 813*fe6060f1SDimitry Andric S += OutputType->getBuiltinStr(); 814*fe6060f1SDimitry Andric for (const auto &T : InputTypes) { 815*fe6060f1SDimitry Andric S += T->getBuiltinStr(); 816*fe6060f1SDimitry Andric } 817*fe6060f1SDimitry Andric return S; 818*fe6060f1SDimitry Andric } 819*fe6060f1SDimitry Andric 820*fe6060f1SDimitry Andric void RVVIntrinsic::emitCodeGenSwitchBody(raw_ostream &OS) const { 821*fe6060f1SDimitry Andric if (!getIRName().empty()) 822*fe6060f1SDimitry Andric OS << " ID = Intrinsic::riscv_" + getIRName() + ";\n"; 823*fe6060f1SDimitry Andric if (NF >= 2) 824*fe6060f1SDimitry Andric OS << " NF = " + utostr(getNF()) + ";\n"; 825*fe6060f1SDimitry Andric if (hasManualCodegen()) { 826*fe6060f1SDimitry Andric OS << ManualCodegen; 827*fe6060f1SDimitry Andric OS << "break;\n"; 828*fe6060f1SDimitry Andric return; 829*fe6060f1SDimitry Andric } 830*fe6060f1SDimitry Andric 831*fe6060f1SDimitry Andric if (isMask()) { 832*fe6060f1SDimitry Andric if (hasVL()) { 833*fe6060f1SDimitry Andric OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n"; 834*fe6060f1SDimitry Andric } else { 835*fe6060f1SDimitry Andric OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n"; 836*fe6060f1SDimitry Andric } 837*fe6060f1SDimitry Andric } 838*fe6060f1SDimitry Andric 839*fe6060f1SDimitry Andric OS << " IntrinsicTypes = {"; 840*fe6060f1SDimitry Andric ListSeparator LS; 841*fe6060f1SDimitry Andric for (const auto &Idx : IntrinsicTypes) { 842*fe6060f1SDimitry Andric if (Idx == -1) 843*fe6060f1SDimitry Andric OS << LS << "ResultType"; 844*fe6060f1SDimitry Andric else 845*fe6060f1SDimitry Andric OS << LS << "Ops[" << Idx << "]->getType()"; 846*fe6060f1SDimitry Andric } 847*fe6060f1SDimitry Andric 848*fe6060f1SDimitry Andric // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is 849*fe6060f1SDimitry Andric // always last operand. 850*fe6060f1SDimitry Andric if (hasVL()) 851*fe6060f1SDimitry Andric OS << ", Ops.back()->getType()"; 852*fe6060f1SDimitry Andric OS << "};\n"; 853*fe6060f1SDimitry Andric OS << " break;\n"; 854*fe6060f1SDimitry Andric } 855*fe6060f1SDimitry Andric 856*fe6060f1SDimitry Andric void RVVIntrinsic::emitIntrinsicMacro(raw_ostream &OS) const { 857*fe6060f1SDimitry Andric OS << "#define " << getName() << "("; 858*fe6060f1SDimitry Andric if (!InputTypes.empty()) { 859*fe6060f1SDimitry Andric ListSeparator LS; 860*fe6060f1SDimitry Andric for (unsigned i = 0, e = InputTypes.size(); i != e; ++i) 861*fe6060f1SDimitry Andric OS << LS << "op" << i; 862*fe6060f1SDimitry Andric } 863*fe6060f1SDimitry Andric OS << ") \\\n"; 864*fe6060f1SDimitry Andric OS << "__builtin_rvv_" << getName() << "("; 865*fe6060f1SDimitry Andric if (!InputTypes.empty()) { 866*fe6060f1SDimitry Andric ListSeparator LS; 867*fe6060f1SDimitry Andric for (unsigned i = 0, e = InputTypes.size(); i != e; ++i) 868*fe6060f1SDimitry Andric OS << LS << "(" << InputTypes[i]->getTypeStr() << ")(op" << i << ")"; 869*fe6060f1SDimitry Andric } 870*fe6060f1SDimitry Andric OS << ")\n"; 871*fe6060f1SDimitry Andric } 872*fe6060f1SDimitry Andric 873*fe6060f1SDimitry Andric void RVVIntrinsic::emitMangledFuncDef(raw_ostream &OS) const { 874*fe6060f1SDimitry Andric OS << "__attribute__((clang_builtin_alias("; 875*fe6060f1SDimitry Andric OS << "__builtin_rvv_" << getName() << ")))\n"; 876*fe6060f1SDimitry Andric OS << OutputType->getTypeStr() << " " << getMangledName() << "("; 877*fe6060f1SDimitry Andric // Emit function arguments 878*fe6060f1SDimitry Andric if (!InputTypes.empty()) { 879*fe6060f1SDimitry Andric ListSeparator LS; 880*fe6060f1SDimitry Andric for (unsigned i = 0; i < InputTypes.size(); ++i) 881*fe6060f1SDimitry Andric OS << LS << InputTypes[i]->getTypeStr() << " op" << i; 882*fe6060f1SDimitry Andric } 883*fe6060f1SDimitry Andric OS << ");\n\n"; 884*fe6060f1SDimitry Andric } 885*fe6060f1SDimitry Andric 886*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 887*fe6060f1SDimitry Andric // RVVEmitter implementation 888*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 889*fe6060f1SDimitry Andric void RVVEmitter::createHeader(raw_ostream &OS) { 890*fe6060f1SDimitry Andric 891*fe6060f1SDimitry Andric OS << "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics " 892*fe6060f1SDimitry Andric "-------------------===\n" 893*fe6060f1SDimitry Andric " *\n" 894*fe6060f1SDimitry Andric " *\n" 895*fe6060f1SDimitry Andric " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " 896*fe6060f1SDimitry Andric "Exceptions.\n" 897*fe6060f1SDimitry Andric " * See https://llvm.org/LICENSE.txt for license information.\n" 898*fe6060f1SDimitry Andric " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 899*fe6060f1SDimitry Andric " *\n" 900*fe6060f1SDimitry Andric " *===-----------------------------------------------------------------" 901*fe6060f1SDimitry Andric "------===\n" 902*fe6060f1SDimitry Andric " */\n\n"; 903*fe6060f1SDimitry Andric 904*fe6060f1SDimitry Andric OS << "#ifndef __RISCV_VECTOR_H\n"; 905*fe6060f1SDimitry Andric OS << "#define __RISCV_VECTOR_H\n\n"; 906*fe6060f1SDimitry Andric 907*fe6060f1SDimitry Andric OS << "#include <stdint.h>\n"; 908*fe6060f1SDimitry Andric OS << "#include <stddef.h>\n\n"; 909*fe6060f1SDimitry Andric 910*fe6060f1SDimitry Andric OS << "#ifndef __riscv_vector\n"; 911*fe6060f1SDimitry Andric OS << "#error \"Vector intrinsics require the vector extension.\"\n"; 912*fe6060f1SDimitry Andric OS << "#endif\n\n"; 913*fe6060f1SDimitry Andric 914*fe6060f1SDimitry Andric OS << "#ifdef __cplusplus\n"; 915*fe6060f1SDimitry Andric OS << "extern \"C\" {\n"; 916*fe6060f1SDimitry Andric OS << "#endif\n\n"; 917*fe6060f1SDimitry Andric 918*fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 919*fe6060f1SDimitry Andric createRVVIntrinsics(Defs); 920*fe6060f1SDimitry Andric 921*fe6060f1SDimitry Andric // Print header code 922*fe6060f1SDimitry Andric if (!HeaderCode.empty()) { 923*fe6060f1SDimitry Andric OS << HeaderCode; 924*fe6060f1SDimitry Andric } 925*fe6060f1SDimitry Andric 926*fe6060f1SDimitry Andric auto printType = [&](auto T) { 927*fe6060f1SDimitry Andric OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr() 928*fe6060f1SDimitry Andric << ";\n"; 929*fe6060f1SDimitry Andric }; 930*fe6060f1SDimitry Andric 931*fe6060f1SDimitry Andric constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3}; 932*fe6060f1SDimitry Andric // Print RVV boolean types. 933*fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 934*fe6060f1SDimitry Andric auto T = computeType('c', Log2LMUL, "m"); 935*fe6060f1SDimitry Andric if (T.hasValue()) 936*fe6060f1SDimitry Andric printType(T.getValue()); 937*fe6060f1SDimitry Andric } 938*fe6060f1SDimitry Andric // Print RVV int/float types. 939*fe6060f1SDimitry Andric for (char I : StringRef("csil")) { 940*fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 941*fe6060f1SDimitry Andric auto T = computeType(I, Log2LMUL, "v"); 942*fe6060f1SDimitry Andric if (T.hasValue()) { 943*fe6060f1SDimitry Andric printType(T.getValue()); 944*fe6060f1SDimitry Andric auto UT = computeType(I, Log2LMUL, "Uv"); 945*fe6060f1SDimitry Andric printType(UT.getValue()); 946*fe6060f1SDimitry Andric } 947*fe6060f1SDimitry Andric } 948*fe6060f1SDimitry Andric } 949*fe6060f1SDimitry Andric OS << "#if defined(__riscv_zfh)\n"; 950*fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 951*fe6060f1SDimitry Andric auto T = computeType('x', Log2LMUL, "v"); 952*fe6060f1SDimitry Andric if (T.hasValue()) 953*fe6060f1SDimitry Andric printType(T.getValue()); 954*fe6060f1SDimitry Andric } 955*fe6060f1SDimitry Andric OS << "#endif\n"; 956*fe6060f1SDimitry Andric 957*fe6060f1SDimitry Andric OS << "#if defined(__riscv_f)\n"; 958*fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 959*fe6060f1SDimitry Andric auto T = computeType('f', Log2LMUL, "v"); 960*fe6060f1SDimitry Andric if (T.hasValue()) 961*fe6060f1SDimitry Andric printType(T.getValue()); 962*fe6060f1SDimitry Andric } 963*fe6060f1SDimitry Andric OS << "#endif\n"; 964*fe6060f1SDimitry Andric 965*fe6060f1SDimitry Andric OS << "#if defined(__riscv_d)\n"; 966*fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 967*fe6060f1SDimitry Andric auto T = computeType('d', Log2LMUL, "v"); 968*fe6060f1SDimitry Andric if (T.hasValue()) 969*fe6060f1SDimitry Andric printType(T.getValue()); 970*fe6060f1SDimitry Andric } 971*fe6060f1SDimitry Andric OS << "#endif\n\n"; 972*fe6060f1SDimitry Andric 973*fe6060f1SDimitry Andric // The same extension include in the same arch guard marco. 974*fe6060f1SDimitry Andric std::stable_sort(Defs.begin(), Defs.end(), 975*fe6060f1SDimitry Andric [](const std::unique_ptr<RVVIntrinsic> &A, 976*fe6060f1SDimitry Andric const std::unique_ptr<RVVIntrinsic> &B) { 977*fe6060f1SDimitry Andric return A->getRISCVExtensions() < B->getRISCVExtensions(); 978*fe6060f1SDimitry Andric }); 979*fe6060f1SDimitry Andric 980*fe6060f1SDimitry Andric // Print intrinsic functions with macro 981*fe6060f1SDimitry Andric emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) { 982*fe6060f1SDimitry Andric Inst.emitIntrinsicMacro(OS); 983*fe6060f1SDimitry Andric }); 984*fe6060f1SDimitry Andric 985*fe6060f1SDimitry Andric OS << "#define __riscv_v_intrinsic_overloading 1\n"; 986*fe6060f1SDimitry Andric 987*fe6060f1SDimitry Andric // Print Overloaded APIs 988*fe6060f1SDimitry Andric OS << "#define __rvv_overloaded static inline " 989*fe6060f1SDimitry Andric "__attribute__((__always_inline__, __nodebug__, __overloadable__))\n"; 990*fe6060f1SDimitry Andric 991*fe6060f1SDimitry Andric emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) { 992*fe6060f1SDimitry Andric if (!Inst.isMask() && !Inst.hasNoMaskedOverloaded()) 993*fe6060f1SDimitry Andric return; 994*fe6060f1SDimitry Andric OS << "__rvv_overloaded "; 995*fe6060f1SDimitry Andric Inst.emitMangledFuncDef(OS); 996*fe6060f1SDimitry Andric }); 997*fe6060f1SDimitry Andric 998*fe6060f1SDimitry Andric OS << "\n#ifdef __cplusplus\n"; 999*fe6060f1SDimitry Andric OS << "}\n"; 1000*fe6060f1SDimitry Andric OS << "#endif // __riscv_vector\n"; 1001*fe6060f1SDimitry Andric OS << "#endif // __RISCV_VECTOR_H\n"; 1002*fe6060f1SDimitry Andric } 1003*fe6060f1SDimitry Andric 1004*fe6060f1SDimitry Andric void RVVEmitter::createBuiltins(raw_ostream &OS) { 1005*fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 1006*fe6060f1SDimitry Andric createRVVIntrinsics(Defs); 1007*fe6060f1SDimitry Andric 1008*fe6060f1SDimitry Andric OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n"; 1009*fe6060f1SDimitry Andric OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, " 1010*fe6060f1SDimitry Andric "ATTRS, \"experimental-v\")\n"; 1011*fe6060f1SDimitry Andric OS << "#endif\n"; 1012*fe6060f1SDimitry Andric for (auto &Def : Defs) { 1013*fe6060f1SDimitry Andric OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getName() << ",\"" 1014*fe6060f1SDimitry Andric << Def->getBuiltinTypeStr() << "\", "; 1015*fe6060f1SDimitry Andric if (!Def->hasSideEffects()) 1016*fe6060f1SDimitry Andric OS << "\"n\")\n"; 1017*fe6060f1SDimitry Andric else 1018*fe6060f1SDimitry Andric OS << "\"\")\n"; 1019*fe6060f1SDimitry Andric } 1020*fe6060f1SDimitry Andric OS << "#undef RISCVV_BUILTIN\n"; 1021*fe6060f1SDimitry Andric } 1022*fe6060f1SDimitry Andric 1023*fe6060f1SDimitry Andric void RVVEmitter::createCodeGen(raw_ostream &OS) { 1024*fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 1025*fe6060f1SDimitry Andric createRVVIntrinsics(Defs); 1026*fe6060f1SDimitry Andric // IR name could be empty, use the stable sort preserves the relative order. 1027*fe6060f1SDimitry Andric std::stable_sort(Defs.begin(), Defs.end(), 1028*fe6060f1SDimitry Andric [](const std::unique_ptr<RVVIntrinsic> &A, 1029*fe6060f1SDimitry Andric const std::unique_ptr<RVVIntrinsic> &B) { 1030*fe6060f1SDimitry Andric return A->getIRName() < B->getIRName(); 1031*fe6060f1SDimitry Andric }); 1032*fe6060f1SDimitry Andric // Print switch body when the ir name or ManualCodegen changes from previous 1033*fe6060f1SDimitry Andric // iteration. 1034*fe6060f1SDimitry Andric RVVIntrinsic *PrevDef = Defs.begin()->get(); 1035*fe6060f1SDimitry Andric for (auto &Def : Defs) { 1036*fe6060f1SDimitry Andric StringRef CurIRName = Def->getIRName(); 1037*fe6060f1SDimitry Andric if (CurIRName != PrevDef->getIRName() || 1038*fe6060f1SDimitry Andric (Def->getManualCodegen() != PrevDef->getManualCodegen())) { 1039*fe6060f1SDimitry Andric PrevDef->emitCodeGenSwitchBody(OS); 1040*fe6060f1SDimitry Andric } 1041*fe6060f1SDimitry Andric PrevDef = Def.get(); 1042*fe6060f1SDimitry Andric OS << "case RISCV::BI__builtin_rvv_" << Def->getName() << ":\n"; 1043*fe6060f1SDimitry Andric } 1044*fe6060f1SDimitry Andric Defs.back()->emitCodeGenSwitchBody(OS); 1045*fe6060f1SDimitry Andric OS << "\n"; 1046*fe6060f1SDimitry Andric } 1047*fe6060f1SDimitry Andric 1048*fe6060f1SDimitry Andric void RVVEmitter::parsePrototypes(StringRef Prototypes, 1049*fe6060f1SDimitry Andric std::function<void(StringRef)> Handler) { 1050*fe6060f1SDimitry Andric const StringRef Primaries("evwqom0ztul"); 1051*fe6060f1SDimitry Andric while (!Prototypes.empty()) { 1052*fe6060f1SDimitry Andric size_t Idx = 0; 1053*fe6060f1SDimitry Andric // Skip over complex prototype because it could contain primitive type 1054*fe6060f1SDimitry Andric // character. 1055*fe6060f1SDimitry Andric if (Prototypes[0] == '(') 1056*fe6060f1SDimitry Andric Idx = Prototypes.find_first_of(')'); 1057*fe6060f1SDimitry Andric Idx = Prototypes.find_first_of(Primaries, Idx); 1058*fe6060f1SDimitry Andric assert(Idx != StringRef::npos); 1059*fe6060f1SDimitry Andric Handler(Prototypes.slice(0, Idx + 1)); 1060*fe6060f1SDimitry Andric Prototypes = Prototypes.drop_front(Idx + 1); 1061*fe6060f1SDimitry Andric } 1062*fe6060f1SDimitry Andric } 1063*fe6060f1SDimitry Andric 1064*fe6060f1SDimitry Andric std::string RVVEmitter::getSuffixStr(char Type, int Log2LMUL, 1065*fe6060f1SDimitry Andric StringRef Prototypes) { 1066*fe6060f1SDimitry Andric SmallVector<std::string> SuffixStrs; 1067*fe6060f1SDimitry Andric parsePrototypes(Prototypes, [&](StringRef Proto) { 1068*fe6060f1SDimitry Andric auto T = computeType(Type, Log2LMUL, Proto); 1069*fe6060f1SDimitry Andric SuffixStrs.push_back(T.getValue()->getShortStr()); 1070*fe6060f1SDimitry Andric }); 1071*fe6060f1SDimitry Andric return join(SuffixStrs, "_"); 1072*fe6060f1SDimitry Andric } 1073*fe6060f1SDimitry Andric 1074*fe6060f1SDimitry Andric void RVVEmitter::createRVVIntrinsics( 1075*fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> &Out) { 1076*fe6060f1SDimitry Andric std::vector<Record *> RV = Records.getAllDerivedDefinitions("RVVBuiltin"); 1077*fe6060f1SDimitry Andric for (auto *R : RV) { 1078*fe6060f1SDimitry Andric StringRef Name = R->getValueAsString("Name"); 1079*fe6060f1SDimitry Andric StringRef SuffixProto = R->getValueAsString("Suffix"); 1080*fe6060f1SDimitry Andric StringRef MangledName = R->getValueAsString("MangledName"); 1081*fe6060f1SDimitry Andric StringRef MangledSuffixProto = R->getValueAsString("MangledSuffix"); 1082*fe6060f1SDimitry Andric StringRef Prototypes = R->getValueAsString("Prototype"); 1083*fe6060f1SDimitry Andric StringRef TypeRange = R->getValueAsString("TypeRange"); 1084*fe6060f1SDimitry Andric bool HasMask = R->getValueAsBit("HasMask"); 1085*fe6060f1SDimitry Andric bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand"); 1086*fe6060f1SDimitry Andric bool HasVL = R->getValueAsBit("HasVL"); 1087*fe6060f1SDimitry Andric bool HasNoMaskedOverloaded = R->getValueAsBit("HasNoMaskedOverloaded"); 1088*fe6060f1SDimitry Andric bool HasSideEffects = R->getValueAsBit("HasSideEffects"); 1089*fe6060f1SDimitry Andric std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL"); 1090*fe6060f1SDimitry Andric StringRef ManualCodegen = R->getValueAsString("ManualCodegen"); 1091*fe6060f1SDimitry Andric StringRef ManualCodegenMask = R->getValueAsString("ManualCodegenMask"); 1092*fe6060f1SDimitry Andric std::vector<int64_t> IntrinsicTypes = 1093*fe6060f1SDimitry Andric R->getValueAsListOfInts("IntrinsicTypes"); 1094*fe6060f1SDimitry Andric StringRef RequiredExtension = R->getValueAsString("RequiredExtension"); 1095*fe6060f1SDimitry Andric StringRef IRName = R->getValueAsString("IRName"); 1096*fe6060f1SDimitry Andric StringRef IRNameMask = R->getValueAsString("IRNameMask"); 1097*fe6060f1SDimitry Andric unsigned NF = R->getValueAsInt("NF"); 1098*fe6060f1SDimitry Andric 1099*fe6060f1SDimitry Andric StringRef HeaderCodeStr = R->getValueAsString("HeaderCode"); 1100*fe6060f1SDimitry Andric bool HasAutoDef = HeaderCodeStr.empty(); 1101*fe6060f1SDimitry Andric if (!HeaderCodeStr.empty()) { 1102*fe6060f1SDimitry Andric HeaderCode += HeaderCodeStr.str(); 1103*fe6060f1SDimitry Andric } 1104*fe6060f1SDimitry Andric // Parse prototype and create a list of primitive type with transformers 1105*fe6060f1SDimitry Andric // (operand) in ProtoSeq. ProtoSeq[0] is output operand. 1106*fe6060f1SDimitry Andric SmallVector<std::string> ProtoSeq; 1107*fe6060f1SDimitry Andric parsePrototypes(Prototypes, [&ProtoSeq](StringRef Proto) { 1108*fe6060f1SDimitry Andric ProtoSeq.push_back(Proto.str()); 1109*fe6060f1SDimitry Andric }); 1110*fe6060f1SDimitry Andric 1111*fe6060f1SDimitry Andric // Compute Builtin types 1112*fe6060f1SDimitry Andric SmallVector<std::string> ProtoMaskSeq = ProtoSeq; 1113*fe6060f1SDimitry Andric if (HasMask) { 1114*fe6060f1SDimitry Andric // If HasMaskedOffOperand, insert result type as first input operand. 1115*fe6060f1SDimitry Andric if (HasMaskedOffOperand) { 1116*fe6060f1SDimitry Andric if (NF == 1) { 1117*fe6060f1SDimitry Andric ProtoMaskSeq.insert(ProtoMaskSeq.begin() + 1, ProtoSeq[0]); 1118*fe6060f1SDimitry Andric } else { 1119*fe6060f1SDimitry Andric // Convert 1120*fe6060f1SDimitry Andric // (void, op0 address, op1 address, ...) 1121*fe6060f1SDimitry Andric // to 1122*fe6060f1SDimitry Andric // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...) 1123*fe6060f1SDimitry Andric for (unsigned I = 0; I < NF; ++I) 1124*fe6060f1SDimitry Andric ProtoMaskSeq.insert( 1125*fe6060f1SDimitry Andric ProtoMaskSeq.begin() + NF + 1, 1126*fe6060f1SDimitry Andric ProtoSeq[1].substr(1)); // Use substr(1) to skip '*' 1127*fe6060f1SDimitry Andric } 1128*fe6060f1SDimitry Andric } 1129*fe6060f1SDimitry Andric if (HasMaskedOffOperand && NF > 1) { 1130*fe6060f1SDimitry Andric // Convert 1131*fe6060f1SDimitry Andric // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...) 1132*fe6060f1SDimitry Andric // to 1133*fe6060f1SDimitry Andric // (void, op0 address, op1 address, ..., mask, maskedoff0, maskedoff1, 1134*fe6060f1SDimitry Andric // ...) 1135*fe6060f1SDimitry Andric ProtoMaskSeq.insert(ProtoMaskSeq.begin() + NF + 1, "m"); 1136*fe6060f1SDimitry Andric } else { 1137*fe6060f1SDimitry Andric // If HasMask, insert 'm' as first input operand. 1138*fe6060f1SDimitry Andric ProtoMaskSeq.insert(ProtoMaskSeq.begin() + 1, "m"); 1139*fe6060f1SDimitry Andric } 1140*fe6060f1SDimitry Andric } 1141*fe6060f1SDimitry Andric // If HasVL, append 'z' to last operand 1142*fe6060f1SDimitry Andric if (HasVL) { 1143*fe6060f1SDimitry Andric ProtoSeq.push_back("z"); 1144*fe6060f1SDimitry Andric ProtoMaskSeq.push_back("z"); 1145*fe6060f1SDimitry Andric } 1146*fe6060f1SDimitry Andric 1147*fe6060f1SDimitry Andric // Create Intrinsics for each type and LMUL. 1148*fe6060f1SDimitry Andric for (char I : TypeRange) { 1149*fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULList) { 1150*fe6060f1SDimitry Andric Optional<RVVTypes> Types = computeTypes(I, Log2LMUL, NF, ProtoSeq); 1151*fe6060f1SDimitry Andric // Ignored to create new intrinsic if there are any illegal types. 1152*fe6060f1SDimitry Andric if (!Types.hasValue()) 1153*fe6060f1SDimitry Andric continue; 1154*fe6060f1SDimitry Andric 1155*fe6060f1SDimitry Andric auto SuffixStr = getSuffixStr(I, Log2LMUL, SuffixProto); 1156*fe6060f1SDimitry Andric auto MangledSuffixStr = getSuffixStr(I, Log2LMUL, MangledSuffixProto); 1157*fe6060f1SDimitry Andric // Create a non-mask intrinsic 1158*fe6060f1SDimitry Andric Out.push_back(std::make_unique<RVVIntrinsic>( 1159*fe6060f1SDimitry Andric Name, SuffixStr, MangledName, MangledSuffixStr, IRName, 1160*fe6060f1SDimitry Andric HasSideEffects, /*IsMask=*/false, /*HasMaskedOffOperand=*/false, 1161*fe6060f1SDimitry Andric HasVL, HasNoMaskedOverloaded, HasAutoDef, ManualCodegen, 1162*fe6060f1SDimitry Andric Types.getValue(), IntrinsicTypes, RequiredExtension, NF)); 1163*fe6060f1SDimitry Andric if (HasMask) { 1164*fe6060f1SDimitry Andric // Create a mask intrinsic 1165*fe6060f1SDimitry Andric Optional<RVVTypes> MaskTypes = 1166*fe6060f1SDimitry Andric computeTypes(I, Log2LMUL, NF, ProtoMaskSeq); 1167*fe6060f1SDimitry Andric Out.push_back(std::make_unique<RVVIntrinsic>( 1168*fe6060f1SDimitry Andric Name, SuffixStr, MangledName, MangledSuffixStr, IRNameMask, 1169*fe6060f1SDimitry Andric HasSideEffects, /*IsMask=*/true, HasMaskedOffOperand, HasVL, 1170*fe6060f1SDimitry Andric HasNoMaskedOverloaded, HasAutoDef, ManualCodegenMask, 1171*fe6060f1SDimitry Andric MaskTypes.getValue(), IntrinsicTypes, RequiredExtension, NF)); 1172*fe6060f1SDimitry Andric } 1173*fe6060f1SDimitry Andric } // end for Log2LMULList 1174*fe6060f1SDimitry Andric } // end for TypeRange 1175*fe6060f1SDimitry Andric } 1176*fe6060f1SDimitry Andric } 1177*fe6060f1SDimitry Andric 1178*fe6060f1SDimitry Andric Optional<RVVTypes> 1179*fe6060f1SDimitry Andric RVVEmitter::computeTypes(BasicType BT, int Log2LMUL, unsigned NF, 1180*fe6060f1SDimitry Andric ArrayRef<std::string> PrototypeSeq) { 1181*fe6060f1SDimitry Andric // LMUL x NF must be less than or equal to 8. 1182*fe6060f1SDimitry Andric if ((Log2LMUL >= 1) && (1 << Log2LMUL) * NF > 8) 1183*fe6060f1SDimitry Andric return llvm::None; 1184*fe6060f1SDimitry Andric 1185*fe6060f1SDimitry Andric RVVTypes Types; 1186*fe6060f1SDimitry Andric for (const std::string &Proto : PrototypeSeq) { 1187*fe6060f1SDimitry Andric auto T = computeType(BT, Log2LMUL, Proto); 1188*fe6060f1SDimitry Andric if (!T.hasValue()) 1189*fe6060f1SDimitry Andric return llvm::None; 1190*fe6060f1SDimitry Andric // Record legal type index 1191*fe6060f1SDimitry Andric Types.push_back(T.getValue()); 1192*fe6060f1SDimitry Andric } 1193*fe6060f1SDimitry Andric return Types; 1194*fe6060f1SDimitry Andric } 1195*fe6060f1SDimitry Andric 1196*fe6060f1SDimitry Andric Optional<RVVTypePtr> RVVEmitter::computeType(BasicType BT, int Log2LMUL, 1197*fe6060f1SDimitry Andric StringRef Proto) { 1198*fe6060f1SDimitry Andric std::string Idx = Twine(Twine(BT) + Twine(Log2LMUL) + Proto).str(); 1199*fe6060f1SDimitry Andric // Search first 1200*fe6060f1SDimitry Andric auto It = LegalTypes.find(Idx); 1201*fe6060f1SDimitry Andric if (It != LegalTypes.end()) 1202*fe6060f1SDimitry Andric return &(It->second); 1203*fe6060f1SDimitry Andric if (IllegalTypes.count(Idx)) 1204*fe6060f1SDimitry Andric return llvm::None; 1205*fe6060f1SDimitry Andric // Compute type and record the result. 1206*fe6060f1SDimitry Andric RVVType T(BT, Log2LMUL, Proto); 1207*fe6060f1SDimitry Andric if (T.isValid()) { 1208*fe6060f1SDimitry Andric // Record legal type index and value. 1209*fe6060f1SDimitry Andric LegalTypes.insert({Idx, T}); 1210*fe6060f1SDimitry Andric return &(LegalTypes[Idx]); 1211*fe6060f1SDimitry Andric } 1212*fe6060f1SDimitry Andric // Record illegal type index. 1213*fe6060f1SDimitry Andric IllegalTypes.insert(Idx); 1214*fe6060f1SDimitry Andric return llvm::None; 1215*fe6060f1SDimitry Andric } 1216*fe6060f1SDimitry Andric 1217*fe6060f1SDimitry Andric void RVVEmitter::emitArchMacroAndBody( 1218*fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &OS, 1219*fe6060f1SDimitry Andric std::function<void(raw_ostream &, const RVVIntrinsic &)> PrintBody) { 1220*fe6060f1SDimitry Andric uint8_t PrevExt = (*Defs.begin())->getRISCVExtensions(); 1221*fe6060f1SDimitry Andric bool NeedEndif = emitExtDefStr(PrevExt, OS); 1222*fe6060f1SDimitry Andric for (auto &Def : Defs) { 1223*fe6060f1SDimitry Andric uint8_t CurExt = Def->getRISCVExtensions(); 1224*fe6060f1SDimitry Andric if (CurExt != PrevExt) { 1225*fe6060f1SDimitry Andric if (NeedEndif) 1226*fe6060f1SDimitry Andric OS << "#endif\n\n"; 1227*fe6060f1SDimitry Andric NeedEndif = emitExtDefStr(CurExt, OS); 1228*fe6060f1SDimitry Andric PrevExt = CurExt; 1229*fe6060f1SDimitry Andric } 1230*fe6060f1SDimitry Andric if (Def->hasAutoDef()) 1231*fe6060f1SDimitry Andric PrintBody(OS, *Def); 1232*fe6060f1SDimitry Andric } 1233*fe6060f1SDimitry Andric if (NeedEndif) 1234*fe6060f1SDimitry Andric OS << "#endif\n\n"; 1235*fe6060f1SDimitry Andric } 1236*fe6060f1SDimitry Andric 1237*fe6060f1SDimitry Andric bool RVVEmitter::emitExtDefStr(uint8_t Extents, raw_ostream &OS) { 1238*fe6060f1SDimitry Andric if (Extents == RISCVExtension::Basic) 1239*fe6060f1SDimitry Andric return false; 1240*fe6060f1SDimitry Andric OS << "#if "; 1241*fe6060f1SDimitry Andric ListSeparator LS(" && "); 1242*fe6060f1SDimitry Andric if (Extents & RISCVExtension::F) 1243*fe6060f1SDimitry Andric OS << LS << "defined(__riscv_f)"; 1244*fe6060f1SDimitry Andric if (Extents & RISCVExtension::D) 1245*fe6060f1SDimitry Andric OS << LS << "defined(__riscv_d)"; 1246*fe6060f1SDimitry Andric if (Extents & RISCVExtension::Zfh) 1247*fe6060f1SDimitry Andric OS << LS << "defined(__riscv_zfh)"; 1248*fe6060f1SDimitry Andric if (Extents & RISCVExtension::Zvamo) 1249*fe6060f1SDimitry Andric OS << LS << "defined(__riscv_zvamo)"; 1250*fe6060f1SDimitry Andric if (Extents & RISCVExtension::Zvlsseg) 1251*fe6060f1SDimitry Andric OS << LS << "defined(__riscv_zvlsseg)"; 1252*fe6060f1SDimitry Andric OS << "\n"; 1253*fe6060f1SDimitry Andric return true; 1254*fe6060f1SDimitry Andric } 1255*fe6060f1SDimitry Andric 1256*fe6060f1SDimitry Andric namespace clang { 1257*fe6060f1SDimitry Andric void EmitRVVHeader(RecordKeeper &Records, raw_ostream &OS) { 1258*fe6060f1SDimitry Andric RVVEmitter(Records).createHeader(OS); 1259*fe6060f1SDimitry Andric } 1260*fe6060f1SDimitry Andric 1261*fe6060f1SDimitry Andric void EmitRVVBuiltins(RecordKeeper &Records, raw_ostream &OS) { 1262*fe6060f1SDimitry Andric RVVEmitter(Records).createBuiltins(OS); 1263*fe6060f1SDimitry Andric } 1264*fe6060f1SDimitry Andric 1265*fe6060f1SDimitry Andric void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 1266*fe6060f1SDimitry Andric RVVEmitter(Records).createCodeGen(OS); 1267*fe6060f1SDimitry Andric } 1268*fe6060f1SDimitry Andric 1269*fe6060f1SDimitry Andric } // End namespace clang 1270