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