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