1*63aa8cf6SRahul Joshi //===-- RISCVVEmitter.cpp - Generate riscv_vector.h for use with clang ----===// 2d6a0560bSZakk Chen // 3d6a0560bSZakk Chen // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4d6a0560bSZakk Chen // See https://llvm.org/LICENSE.txt for license information. 5d6a0560bSZakk Chen // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6d6a0560bSZakk Chen // 7d6a0560bSZakk Chen //===----------------------------------------------------------------------===// 8d6a0560bSZakk Chen // 9821547caSZakk Chen // This tablegen backend is responsible for emitting riscv_vector.h which 10821547caSZakk Chen // includes a declaration and definition of each intrinsic functions specified 11821547caSZakk Chen // in https://github.com/riscv/rvv-intrinsic-doc. 12d6a0560bSZakk Chen // 13d6a0560bSZakk Chen // See also the documentation in include/clang/Basic/riscv_vector.td. 14d6a0560bSZakk Chen // 15d6a0560bSZakk Chen //===----------------------------------------------------------------------===// 16d6a0560bSZakk Chen 17f26c41e8SKito Cheng #include "clang/Support/RISCVVIntrinsicUtils.h" 18d6a0560bSZakk Chen #include "llvm/ADT/ArrayRef.h" 19d6a0560bSZakk Chen #include "llvm/ADT/StringExtras.h" 20d6a0560bSZakk Chen #include "llvm/ADT/StringMap.h" 217a5cb15eSKito Cheng #include "llvm/ADT/StringSwitch.h" 22d6a0560bSZakk Chen #include "llvm/ADT/Twine.h" 239773cad5SCraig Topper #include "llvm/TableGen/Error.h" 24d6a0560bSZakk Chen #include "llvm/TableGen/Record.h" 259cf4419eSKazu Hirata #include <optional> 26d6a0560bSZakk Chen 27d6a0560bSZakk Chen using namespace llvm; 28f26c41e8SKito Cheng using namespace clang::RISCV; 29d6a0560bSZakk Chen 30d6a0560bSZakk Chen namespace { 317a5cb15eSKito Cheng struct SemaRecord { 327a5cb15eSKito Cheng // Intrinsic name, e.g. vadd_vv 337a5cb15eSKito Cheng std::string Name; 347a5cb15eSKito Cheng 357a5cb15eSKito Cheng // Overloaded intrinsic name, could be empty if can be computed from Name 367a5cb15eSKito Cheng // e.g. vadd 377a5cb15eSKito Cheng std::string OverloadedName; 387a5cb15eSKito Cheng 397a5cb15eSKito Cheng // Supported type, mask of BasicType. 407a5cb15eSKito Cheng unsigned TypeRangeMask; 417a5cb15eSKito Cheng 427a5cb15eSKito Cheng // Supported LMUL. 437a5cb15eSKito Cheng unsigned Log2LMULMask; 447a5cb15eSKito Cheng 457a5cb15eSKito Cheng // Required extensions for this intrinsic. 4609058654SEric Biggers uint32_t RequiredExtensions; 477a5cb15eSKito Cheng 487a5cb15eSKito Cheng // Prototype for this intrinsic. 497a5cb15eSKito Cheng SmallVector<PrototypeDescriptor> Prototype; 507a5cb15eSKito Cheng 517a5cb15eSKito Cheng // Suffix of intrinsic name. 527a5cb15eSKito Cheng SmallVector<PrototypeDescriptor> Suffix; 537a5cb15eSKito Cheng 547a5cb15eSKito Cheng // Suffix of overloaded intrinsic name. 557a5cb15eSKito Cheng SmallVector<PrototypeDescriptor> OverloadedSuffix; 567a5cb15eSKito Cheng 577a5cb15eSKito Cheng // Number of field, large than 1 if it's segment load/store. 587a5cb15eSKito Cheng unsigned NF; 5993f8657cSZakk Chen 6093f8657cSZakk Chen bool HasMasked :1; 6193f8657cSZakk Chen bool HasVL :1; 6293f8657cSZakk Chen bool HasMaskedOffOperand :1; 6371fd6616SZakk Chen bool HasTailPolicy : 1; 6471fd6616SZakk Chen bool HasMaskPolicy : 1; 6576482078SeopXD bool HasFRMRoundModeOp : 1; 660019226cSeopXD bool IsTuple : 1; 6723bdca2cSVlad Serebrennikov LLVM_PREFERRED_TYPE(PolicyScheme) 6871fd6616SZakk Chen uint8_t UnMaskedPolicyScheme : 2; 6923bdca2cSVlad Serebrennikov LLVM_PREFERRED_TYPE(PolicyScheme) 7071fd6616SZakk Chen uint8_t MaskedPolicyScheme : 2; 717a5cb15eSKito Cheng }; 727a5cb15eSKito Cheng 737a5cb15eSKito Cheng // Compressed function signature table. 747a5cb15eSKito Cheng class SemaSignatureTable { 757a5cb15eSKito Cheng private: 767a5cb15eSKito Cheng std::vector<PrototypeDescriptor> SignatureTable; 777a5cb15eSKito Cheng 787a5cb15eSKito Cheng void insert(ArrayRef<PrototypeDescriptor> Signature); 797a5cb15eSKito Cheng 807a5cb15eSKito Cheng public: 817a5cb15eSKito Cheng static constexpr unsigned INVALID_INDEX = ~0U; 827a5cb15eSKito Cheng 837a5cb15eSKito Cheng // Create compressed signature table from SemaRecords. 847a5cb15eSKito Cheng void init(ArrayRef<SemaRecord> SemaRecords); 857a5cb15eSKito Cheng 867a5cb15eSKito Cheng // Query the Signature, return INVALID_INDEX if not found. 877a5cb15eSKito Cheng unsigned getIndex(ArrayRef<PrototypeDescriptor> Signature); 887a5cb15eSKito Cheng 897a5cb15eSKito Cheng /// Print signature table in RVVHeader Record to \p OS 907a5cb15eSKito Cheng void print(raw_ostream &OS); 917a5cb15eSKito Cheng }; 927a5cb15eSKito Cheng 93d6a0560bSZakk Chen class RVVEmitter { 94d6a0560bSZakk Chen private: 95974fa852SRahul Joshi const RecordKeeper &Records; 963fe89be8SKito Cheng RVVTypeCache TypeCache; 97d6a0560bSZakk Chen 98d6a0560bSZakk Chen public: 99974fa852SRahul Joshi RVVEmitter(const RecordKeeper &R) : Records(R) {} 100d6a0560bSZakk Chen 101d6a0560bSZakk Chen /// Emit riscv_vector.h 102d6a0560bSZakk Chen void createHeader(raw_ostream &o); 103d6a0560bSZakk Chen 104d6a0560bSZakk Chen /// Emit all the __builtin prototypes and code needed by Sema. 105d6a0560bSZakk Chen void createBuiltins(raw_ostream &o); 106d6a0560bSZakk Chen 107d6a0560bSZakk Chen /// Emit all the information needed to map builtin -> LLVM IR intrinsic. 108d6a0560bSZakk Chen void createCodeGen(raw_ostream &o); 109d6a0560bSZakk Chen 1107a5cb15eSKito Cheng /// Emit all the information needed by SemaRISCVVectorLookup.cpp. 1117a5cb15eSKito Cheng /// We've large number of intrinsic function for RVV, creating a customized 1127a5cb15eSKito Cheng /// could speed up the compilation time. 1137a5cb15eSKito Cheng void createSema(raw_ostream &o); 1147a5cb15eSKito Cheng 115d6a0560bSZakk Chen private: 1167a5cb15eSKito Cheng /// Create all intrinsics and add them to \p Out and SemaRecords. 1177a5cb15eSKito Cheng void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out, 1187a5cb15eSKito Cheng std::vector<SemaRecord> *SemaRecords = nullptr); 1197a5cb15eSKito Cheng /// Create all intrinsic records and SemaSignatureTable from SemaRecords. 1207a5cb15eSKito Cheng void createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out, 1217a5cb15eSKito Cheng SemaSignatureTable &SST, 1227a5cb15eSKito Cheng ArrayRef<SemaRecord> SemaRecords); 1237a5cb15eSKito Cheng 12423d60ce1SZakk Chen /// Print HeaderCode in RVVHeader Record to \p Out 12523d60ce1SZakk Chen void printHeaderCode(raw_ostream &OS); 126d6a0560bSZakk Chen }; 127d6a0560bSZakk Chen 128d6a0560bSZakk Chen } // namespace 129d6a0560bSZakk Chen 1307ff0bf57SKito Cheng static BasicType ParseBasicType(char c) { 1317ff0bf57SKito Cheng switch (c) { 1327ff0bf57SKito Cheng case 'c': 1337ff0bf57SKito Cheng return BasicType::Int8; 1347ff0bf57SKito Cheng break; 1357ff0bf57SKito Cheng case 's': 1367ff0bf57SKito Cheng return BasicType::Int16; 1377ff0bf57SKito Cheng break; 1387ff0bf57SKito Cheng case 'i': 1397ff0bf57SKito Cheng return BasicType::Int32; 1407ff0bf57SKito Cheng break; 1417ff0bf57SKito Cheng case 'l': 1427ff0bf57SKito Cheng return BasicType::Int64; 1437ff0bf57SKito Cheng break; 1447ff0bf57SKito Cheng case 'x': 1457ff0bf57SKito Cheng return BasicType::Float16; 1467ff0bf57SKito Cheng break; 1477ff0bf57SKito Cheng case 'f': 1487ff0bf57SKito Cheng return BasicType::Float32; 1497ff0bf57SKito Cheng break; 1507ff0bf57SKito Cheng case 'd': 1517ff0bf57SKito Cheng return BasicType::Float64; 1527ff0bf57SKito Cheng break; 153fa8347fbSMichael Maitland case 'y': 154fbdf6e27SShao-Ce SUN return BasicType::BFloat16; 155fbdf6e27SShao-Ce SUN break; 1567ff0bf57SKito Cheng default: 1577ff0bf57SKito Cheng return BasicType::Unknown; 1587ff0bf57SKito Cheng } 1597ff0bf57SKito Cheng } 1607ff0bf57SKito Cheng 1615847ec4dSeopXD static VectorTypeModifier getTupleVTM(unsigned NF) { 1625847ec4dSeopXD assert(2 <= NF && NF <= 8 && "2 <= NF <= 8"); 1635847ec4dSeopXD return static_cast<VectorTypeModifier>( 1645847ec4dSeopXD static_cast<uint8_t>(VectorTypeModifier::Tuple2) + (NF - 2)); 1655847ec4dSeopXD } 1665847ec4dSeopXD 16746f953d1SBrandon Wu static unsigned getIndexedLoadStorePtrIdx(const RVVIntrinsic *RVVI) { 16846f953d1SBrandon Wu // We need a special rule for segment load/store since the data width is not 169922992a2SJay Foad // encoded in the intrinsic name itself. 17046f953d1SBrandon Wu const StringRef IRName = RVVI->getIRName(); 17146f953d1SBrandon Wu constexpr unsigned RVV_VTA = 0x1; 17246f953d1SBrandon Wu constexpr unsigned RVV_VMA = 0x2; 17346f953d1SBrandon Wu 17446f953d1SBrandon Wu if (IRName.starts_with("vloxseg") || IRName.starts_with("vluxseg")) { 17546f953d1SBrandon Wu bool NoPassthru = 17646f953d1SBrandon Wu (RVVI->isMasked() && (RVVI->getPolicyAttrsBits() & RVV_VTA) && 17746f953d1SBrandon Wu (RVVI->getPolicyAttrsBits() & RVV_VMA)) || 17846f953d1SBrandon Wu (!RVVI->isMasked() && (RVVI->getPolicyAttrsBits() & RVV_VTA)); 17946f953d1SBrandon Wu return RVVI->isMasked() ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1; 18046f953d1SBrandon Wu } 18146f953d1SBrandon Wu if (IRName.starts_with("vsoxseg") || IRName.starts_with("vsuxseg")) 18246f953d1SBrandon Wu return RVVI->isMasked() ? 1 : 0; 18346f953d1SBrandon Wu 18446f953d1SBrandon Wu return (unsigned)-1; 18546f953d1SBrandon Wu } 18646f953d1SBrandon Wu 187239127d7SBrandon Wu // This function is used to get the log2SEW of each segment load/store, this 188239127d7SBrandon Wu // prevent to add a member to RVVIntrinsic. 189239127d7SBrandon Wu static unsigned getSegInstLog2SEW(StringRef InstName) { 190239127d7SBrandon Wu // clang-format off 19146f953d1SBrandon Wu // We need a special rule for indexed segment load/store since the data width 192922992a2SJay Foad // is not encoded in the intrinsic name itself. 19346f953d1SBrandon Wu if (InstName.starts_with("vloxseg") || InstName.starts_with("vluxseg") || 19446f953d1SBrandon Wu InstName.starts_with("vsoxseg") || InstName.starts_with("vsuxseg")) 19546f953d1SBrandon Wu return (unsigned)-1; 19646f953d1SBrandon Wu 197239127d7SBrandon Wu #define KEY_VAL(KEY, VAL) {#KEY, VAL} 198239127d7SBrandon Wu #define KEY_VAL_ALL_W_POLICY(KEY, VAL) \ 199239127d7SBrandon Wu KEY_VAL(KEY, VAL), \ 200239127d7SBrandon Wu KEY_VAL(KEY ## _tu, VAL), \ 201239127d7SBrandon Wu KEY_VAL(KEY ## _tum, VAL), \ 202239127d7SBrandon Wu KEY_VAL(KEY ## _tumu, VAL), \ 203239127d7SBrandon Wu KEY_VAL(KEY ## _mu, VAL) 204239127d7SBrandon Wu 20546f953d1SBrandon Wu #define KEY_VAL_ALL_NF_BASE(MACRO_NAME, NAME, SEW, LOG2SEW, FF) \ 20646f953d1SBrandon Wu MACRO_NAME(NAME ## 2e ## SEW ## FF, LOG2SEW), \ 20746f953d1SBrandon Wu MACRO_NAME(NAME ## 3e ## SEW ## FF, LOG2SEW), \ 20846f953d1SBrandon Wu MACRO_NAME(NAME ## 4e ## SEW ## FF, LOG2SEW), \ 20946f953d1SBrandon Wu MACRO_NAME(NAME ## 5e ## SEW ## FF, LOG2SEW), \ 21046f953d1SBrandon Wu MACRO_NAME(NAME ## 6e ## SEW ## FF, LOG2SEW), \ 21146f953d1SBrandon Wu MACRO_NAME(NAME ## 7e ## SEW ## FF, LOG2SEW), \ 21246f953d1SBrandon Wu MACRO_NAME(NAME ## 8e ## SEW ## FF, LOG2SEW) 213239127d7SBrandon Wu 214239127d7SBrandon Wu #define KEY_VAL_ALL_NF(NAME, SEW, LOG2SEW) \ 215239127d7SBrandon Wu KEY_VAL_ALL_NF_BASE(KEY_VAL_ALL_W_POLICY, NAME, SEW, LOG2SEW,) 216239127d7SBrandon Wu 217239127d7SBrandon Wu #define KEY_VAL_FF_ALL_NF(NAME, SEW, LOG2SEW) \ 21846f953d1SBrandon Wu KEY_VAL_ALL_NF_BASE(KEY_VAL_ALL_W_POLICY, NAME, SEW, LOG2SEW, ff) 219239127d7SBrandon Wu 220239127d7SBrandon Wu #define KEY_VAL_ALL_NF_SEW_BASE(MACRO_NAME, NAME) \ 221239127d7SBrandon Wu MACRO_NAME(NAME, 8, 3), \ 222239127d7SBrandon Wu MACRO_NAME(NAME, 16, 4), \ 223239127d7SBrandon Wu MACRO_NAME(NAME, 32, 5), \ 224239127d7SBrandon Wu MACRO_NAME(NAME, 64, 6) 225239127d7SBrandon Wu 226239127d7SBrandon Wu #define KEY_VAL_ALL_NF_SEW(NAME) \ 227239127d7SBrandon Wu KEY_VAL_ALL_NF_SEW_BASE(KEY_VAL_ALL_NF, NAME) 228239127d7SBrandon Wu 229239127d7SBrandon Wu #define KEY_VAL_FF_ALL_NF_SEW(NAME) \ 230239127d7SBrandon Wu KEY_VAL_ALL_NF_SEW_BASE(KEY_VAL_FF_ALL_NF, NAME) 231239127d7SBrandon Wu // clang-format on 232239127d7SBrandon Wu 233239127d7SBrandon Wu static StringMap<unsigned> SegInsts = { 234239127d7SBrandon Wu KEY_VAL_ALL_NF_SEW(vlseg), KEY_VAL_FF_ALL_NF_SEW(vlseg), 23546f953d1SBrandon Wu KEY_VAL_ALL_NF_SEW(vlsseg), KEY_VAL_ALL_NF_SEW(vsseg), 23646f953d1SBrandon Wu KEY_VAL_ALL_NF_SEW(vssseg)}; 237239127d7SBrandon Wu 238239127d7SBrandon Wu #undef KEY_VAL_ALL_NF_SEW 239239127d7SBrandon Wu #undef KEY_VAL_ALL_NF 240239127d7SBrandon Wu #undef KEY_VAL 241239127d7SBrandon Wu 242239127d7SBrandon Wu return SegInsts.lookup(InstName); 243239127d7SBrandon Wu } 244239127d7SBrandon Wu 245f26c41e8SKito Cheng void emitCodeGenSwitchBody(const RVVIntrinsic *RVVI, raw_ostream &OS) { 246f26c41e8SKito Cheng if (!RVVI->getIRName().empty()) 247f26c41e8SKito Cheng OS << " ID = Intrinsic::riscv_" + RVVI->getIRName() + ";\n"; 2485a1c6ec1SeopXD 2491deb6bceSeopXD OS << " PolicyAttrs = " << RVVI->getPolicyAttrsBits() << ";\n"; 250239127d7SBrandon Wu OS << " SegInstSEW = " << getSegInstLog2SEW(RVVI->getOverloadedName()) 251239127d7SBrandon Wu << ";\n"; 25271fd6616SZakk Chen 253f26c41e8SKito Cheng if (RVVI->hasManualCodegen()) { 2545a1c6ec1SeopXD OS << "IsMasked = " << (RVVI->isMasked() ? "true" : "false") << ";\n"; 25546f953d1SBrandon Wu 25646f953d1SBrandon Wu // Skip the non-indexed load/store and compatible header load/store. 25746f953d1SBrandon Wu OS << "if (SegInstSEW == (unsigned)-1) {\n"; 25846f953d1SBrandon Wu OS << " auto PointeeType = E->getArg(" << getIndexedLoadStorePtrIdx(RVVI) 25946f953d1SBrandon Wu << " )->getType()->getPointeeType();\n"; 26046f953d1SBrandon Wu OS << " SegInstSEW = " 26146f953d1SBrandon Wu " llvm::Log2_64(getContext().getTypeSize(PointeeType));\n}\n"; 26246f953d1SBrandon Wu 263f26c41e8SKito Cheng OS << RVVI->getManualCodegen(); 26495c0125fSZakk Chen OS << "break;\n"; 26595c0125fSZakk Chen return; 26695c0125fSZakk Chen } 267cfe3b000SCraig Topper 268939352b6SYeting Kuo for (const auto &I : enumerate(RVVI->getInputTypes())) { 269939352b6SYeting Kuo if (I.value()->isPointer()) { 270939352b6SYeting Kuo assert(RVVI->getIntrinsicTypes().front() == -1 && 271939352b6SYeting Kuo "RVVI should be vector load intrinsic."); 272939352b6SYeting Kuo } 273939352b6SYeting Kuo } 274939352b6SYeting Kuo 275f26c41e8SKito Cheng if (RVVI->isMasked()) { 276f26c41e8SKito Cheng if (RVVI->hasVL()) { 277cfe3b000SCraig Topper OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n"; 278f26c41e8SKito Cheng if (RVVI->hasPolicyOperand()) 2795158cfefSHsiangkai Wang OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType()," 2801deb6bceSeopXD " PolicyAttrs));\n"; 2811deb6bceSeopXD if (RVVI->hasMaskedOffOperand() && RVVI->getPolicyAttrs().isTAMAPolicy()) 2821972fb23SeopXD OS << " Ops.insert(Ops.begin(), " 2831972fb23SeopXD "llvm::PoisonValue::get(ResultType));\n"; 284dffdca85SZakk Chen // Masked reduction cases. 285dffdca85SZakk Chen if (!RVVI->hasMaskedOffOperand() && RVVI->hasPassthruOperand() && 2861deb6bceSeopXD RVVI->getPolicyAttrs().isTAMAPolicy()) 2871972fb23SeopXD OS << " Ops.insert(Ops.begin(), " 2881972fb23SeopXD "llvm::PoisonValue::get(ResultType));\n"; 289cfe3b000SCraig Topper } else { 290cfe3b000SCraig Topper OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n"; 291cfe3b000SCraig Topper } 292ca783124SZakk Chen } else { 293f26c41e8SKito Cheng if (RVVI->hasPolicyOperand()) 294ca783124SZakk Chen OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(), " 2951deb6bceSeopXD "PolicyAttrs));\n"; 2961deb6bceSeopXD else if (RVVI->hasPassthruOperand() && RVVI->getPolicyAttrs().isTAPolicy()) 2971972fb23SeopXD OS << " Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));\n"; 298ca783124SZakk Chen } 299cfe3b000SCraig Topper 300d6a0560bSZakk Chen OS << " IntrinsicTypes = {"; 301d6a0560bSZakk Chen ListSeparator LS; 302f26c41e8SKito Cheng for (const auto &Idx : RVVI->getIntrinsicTypes()) { 303d6a0560bSZakk Chen if (Idx == -1) 304d6a0560bSZakk Chen OS << LS << "ResultType"; 305d6a0560bSZakk Chen else 306d6a0560bSZakk Chen OS << LS << "Ops[" << Idx << "]->getType()"; 307d6a0560bSZakk Chen } 308d6a0560bSZakk Chen 309d6a0560bSZakk Chen // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is 310d6a0560bSZakk Chen // always last operand. 311f26c41e8SKito Cheng if (RVVI->hasVL()) 312cfe3b000SCraig Topper OS << ", Ops.back()->getType()"; 313d6a0560bSZakk Chen OS << "};\n"; 314d6a0560bSZakk Chen OS << " break;\n"; 315d6a0560bSZakk Chen } 316d6a0560bSZakk Chen 3177a5cb15eSKito Cheng //===----------------------------------------------------------------------===// 3187a5cb15eSKito Cheng // SemaSignatureTable implementation 3197a5cb15eSKito Cheng //===----------------------------------------------------------------------===// 3207a5cb15eSKito Cheng void SemaSignatureTable::init(ArrayRef<SemaRecord> SemaRecords) { 3217a5cb15eSKito Cheng // Sort signature entries by length, let longer signature insert first, to 3227a5cb15eSKito Cheng // make it more possible to reuse table entries, that can reduce ~10% table 3237a5cb15eSKito Cheng // size. 3247a5cb15eSKito Cheng struct Compare { 3257a5cb15eSKito Cheng bool operator()(const SmallVector<PrototypeDescriptor> &A, 3267a5cb15eSKito Cheng const SmallVector<PrototypeDescriptor> &B) const { 3277a5cb15eSKito Cheng if (A.size() != B.size()) 3287a5cb15eSKito Cheng return A.size() > B.size(); 3297a5cb15eSKito Cheng 3307a5cb15eSKito Cheng size_t Len = A.size(); 3317a5cb15eSKito Cheng for (size_t i = 0; i < Len; ++i) { 3327a5cb15eSKito Cheng if (A[i] != B[i]) 3337a5cb15eSKito Cheng return A[i] < B[i]; 334d6a0560bSZakk Chen } 335d6a0560bSZakk Chen 3367a5cb15eSKito Cheng return false; 337d6a0560bSZakk Chen } 3387a5cb15eSKito Cheng }; 3397a5cb15eSKito Cheng 3407a5cb15eSKito Cheng std::set<SmallVector<PrototypeDescriptor>, Compare> Signatures; 3417a5cb15eSKito Cheng auto InsertToSignatureSet = 3427a5cb15eSKito Cheng [&](const SmallVector<PrototypeDescriptor> &Signature) { 3437a5cb15eSKito Cheng if (Signature.empty()) 3447a5cb15eSKito Cheng return; 3457a5cb15eSKito Cheng 3467a5cb15eSKito Cheng Signatures.insert(Signature); 3477a5cb15eSKito Cheng }; 3487a5cb15eSKito Cheng 3497a5cb15eSKito Cheng assert(!SemaRecords.empty()); 3507a5cb15eSKito Cheng 35127bba42fSKazu Hirata for (const SemaRecord &SR : SemaRecords) { 3527a5cb15eSKito Cheng InsertToSignatureSet(SR.Prototype); 3537a5cb15eSKito Cheng InsertToSignatureSet(SR.Suffix); 3547a5cb15eSKito Cheng InsertToSignatureSet(SR.OverloadedSuffix); 35527bba42fSKazu Hirata } 3567a5cb15eSKito Cheng 35727bba42fSKazu Hirata for (auto &Sig : Signatures) 35827bba42fSKazu Hirata insert(Sig); 3597a5cb15eSKito Cheng } 3607a5cb15eSKito Cheng 3617a5cb15eSKito Cheng void SemaSignatureTable::insert(ArrayRef<PrototypeDescriptor> Signature) { 3627a5cb15eSKito Cheng if (getIndex(Signature) != INVALID_INDEX) 3637a5cb15eSKito Cheng return; 3647a5cb15eSKito Cheng 3657a5cb15eSKito Cheng // Insert Signature into SignatureTable if not found in the table. 3667a5cb15eSKito Cheng SignatureTable.insert(SignatureTable.begin(), Signature.begin(), 3677a5cb15eSKito Cheng Signature.end()); 3687a5cb15eSKito Cheng } 3697a5cb15eSKito Cheng 3707a5cb15eSKito Cheng unsigned SemaSignatureTable::getIndex(ArrayRef<PrototypeDescriptor> Signature) { 3717a5cb15eSKito Cheng // Empty signature could be point into any index since there is length 3727a5cb15eSKito Cheng // field when we use, so just always point it to 0. 3737a5cb15eSKito Cheng if (Signature.empty()) 3747a5cb15eSKito Cheng return 0; 3757a5cb15eSKito Cheng 3767a5cb15eSKito Cheng // Checking Signature already in table or not. 377bccf2c84SJianjian Guan if (Signature.size() <= SignatureTable.size()) { 3787a5cb15eSKito Cheng size_t Bound = SignatureTable.size() - Signature.size() + 1; 3797a5cb15eSKito Cheng for (size_t Index = 0; Index < Bound; ++Index) { 3807a5cb15eSKito Cheng if (equal(Signature.begin(), Signature.end(), 3817a5cb15eSKito Cheng SignatureTable.begin() + Index)) 3827a5cb15eSKito Cheng return Index; 3837a5cb15eSKito Cheng } 3847a5cb15eSKito Cheng } 3857a5cb15eSKito Cheng 3867a5cb15eSKito Cheng return INVALID_INDEX; 3877a5cb15eSKito Cheng } 3887a5cb15eSKito Cheng 3897a5cb15eSKito Cheng void SemaSignatureTable::print(raw_ostream &OS) { 3907a5cb15eSKito Cheng for (const auto &Sig : SignatureTable) 3917a5cb15eSKito Cheng OS << "PrototypeDescriptor(" << static_cast<int>(Sig.PT) << ", " 3927a5cb15eSKito Cheng << static_cast<int>(Sig.VTM) << ", " << static_cast<int>(Sig.TM) 3937a5cb15eSKito Cheng << "),\n"; 394d8fa5ef6SHsiangkai Wang } 395d6a0560bSZakk Chen 396d6a0560bSZakk Chen //===----------------------------------------------------------------------===// 397d6a0560bSZakk Chen // RVVEmitter implementation 398d6a0560bSZakk Chen //===----------------------------------------------------------------------===// 399d6a0560bSZakk Chen void RVVEmitter::createHeader(raw_ostream &OS) { 400d6a0560bSZakk Chen 401d6a0560bSZakk Chen OS << "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics " 402d6a0560bSZakk Chen "-------------------===\n" 403d6a0560bSZakk Chen " *\n" 404d6a0560bSZakk Chen " *\n" 405d6a0560bSZakk Chen " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " 406d6a0560bSZakk Chen "Exceptions.\n" 407d6a0560bSZakk Chen " * See https://llvm.org/LICENSE.txt for license information.\n" 408d6a0560bSZakk Chen " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 409d6a0560bSZakk Chen " *\n" 410d6a0560bSZakk Chen " *===-----------------------------------------------------------------" 411d6a0560bSZakk Chen "------===\n" 412d6a0560bSZakk Chen " */\n\n"; 413d6a0560bSZakk Chen 414d6a0560bSZakk Chen OS << "#ifndef __RISCV_VECTOR_H\n"; 415d6a0560bSZakk Chen OS << "#define __RISCV_VECTOR_H\n\n"; 416d6a0560bSZakk Chen 417d6a0560bSZakk Chen OS << "#include <stdint.h>\n"; 418d6a0560bSZakk Chen OS << "#include <stddef.h>\n\n"; 419d6a0560bSZakk Chen 420d6a0560bSZakk Chen OS << "#ifdef __cplusplus\n"; 421d6a0560bSZakk Chen OS << "extern \"C\" {\n"; 422d6a0560bSZakk Chen OS << "#endif\n\n"; 423d6a0560bSZakk Chen 4247a5cb15eSKito Cheng OS << "#pragma clang riscv intrinsic vector\n\n"; 4255158cfefSHsiangkai Wang 4267a5cb15eSKito Cheng printHeaderCode(OS); 427d6a0560bSZakk Chen 428d6a0560bSZakk Chen auto printType = [&](auto T) { 429d6a0560bSZakk Chen OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr() 430d6a0560bSZakk Chen << ";\n"; 431d6a0560bSZakk Chen }; 432d6a0560bSZakk Chen 433d6a0560bSZakk Chen constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3}; 434d6a0560bSZakk Chen // Print RVV boolean types. 435d6a0560bSZakk Chen for (int Log2LMUL : Log2LMULs) { 4363fe89be8SKito Cheng auto T = TypeCache.computeType(BasicType::Int8, Log2LMUL, 4377ff0bf57SKito Cheng PrototypeDescriptor::Mask); 43897afce08SKazu Hirata if (T) 439fc6ca0d0SFangrui Song printType(*T); 440d6a0560bSZakk Chen } 441d6a0560bSZakk Chen // Print RVV int/float types. 442d6a0560bSZakk Chen for (char I : StringRef("csil")) { 4437ff0bf57SKito Cheng BasicType BT = ParseBasicType(I); 444d6a0560bSZakk Chen for (int Log2LMUL : Log2LMULs) { 4453fe89be8SKito Cheng auto T = TypeCache.computeType(BT, Log2LMUL, PrototypeDescriptor::Vector); 44697afce08SKazu Hirata if (T) { 447fc6ca0d0SFangrui Song printType(*T); 4483fe89be8SKito Cheng auto UT = TypeCache.computeType( 4497ff0bf57SKito Cheng BT, Log2LMUL, 4507ff0bf57SKito Cheng PrototypeDescriptor(BaseTypeModifier::Vector, 4517ff0bf57SKito Cheng VectorTypeModifier::NoModifier, 4527ff0bf57SKito Cheng TypeModifier::UnsignedInteger)); 453fc6ca0d0SFangrui Song printType(*UT); 454d6a0560bSZakk Chen } 4555847ec4dSeopXD for (int NF = 2; NF <= 8; ++NF) { 4560019226cSeopXD auto TupleT = TypeCache.computeType( 4570019226cSeopXD BT, Log2LMUL, 4585847ec4dSeopXD PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF), 4590019226cSeopXD TypeModifier::SignedInteger)); 4605847ec4dSeopXD auto TupleUT = TypeCache.computeType( 4615847ec4dSeopXD BT, Log2LMUL, 4625847ec4dSeopXD PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF), 4635847ec4dSeopXD TypeModifier::UnsignedInteger)); 4640019226cSeopXD if (TupleT) 4650019226cSeopXD printType(*TupleT); 4665847ec4dSeopXD if (TupleUT) 4675847ec4dSeopXD printType(*TupleUT); 4680019226cSeopXD } 469d6a0560bSZakk Chen } 470d6a0560bSZakk Chen } 471235e90c1SeopXD 472fbdf6e27SShao-Ce SUN for (BasicType BT : {BasicType::Float16, BasicType::Float32, 473fbdf6e27SShao-Ce SUN BasicType::Float64, BasicType::BFloat16}) { 474d6a0560bSZakk Chen for (int Log2LMUL : Log2LMULs) { 4759efa4cdbSeopXD auto T = TypeCache.computeType(BT, Log2LMUL, PrototypeDescriptor::Vector); 47697afce08SKazu Hirata if (T) 477fc6ca0d0SFangrui Song printType(*T); 4785847ec4dSeopXD for (int NF = 2; NF <= 8; ++NF) { 4795847ec4dSeopXD auto TupleT = TypeCache.computeType( 4805847ec4dSeopXD BT, Log2LMUL, 4815847ec4dSeopXD PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF), 4821c937819SYueh-Ting (eop) Chen (BT == BasicType::BFloat16 4831c937819SYueh-Ting (eop) Chen ? TypeModifier::BFloat 4841c937819SYueh-Ting (eop) Chen : TypeModifier::Float))); 4855847ec4dSeopXD if (TupleT) 4865847ec4dSeopXD printType(*TupleT); 4875847ec4dSeopXD } 488d6a0560bSZakk Chen } 489d6a0560bSZakk Chen } 490d6a0560bSZakk Chen 491d6a0560bSZakk Chen OS << "\n#ifdef __cplusplus\n"; 492d6a0560bSZakk Chen OS << "}\n"; 493477f5f4fSjacquesguan OS << "#endif // __cplusplus\n"; 494d6a0560bSZakk Chen OS << "#endif // __RISCV_VECTOR_H\n"; 495d6a0560bSZakk Chen } 496d6a0560bSZakk Chen 497d6a0560bSZakk Chen void RVVEmitter::createBuiltins(raw_ostream &OS) { 498d6a0560bSZakk Chen std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 499d6a0560bSZakk Chen createRVVIntrinsics(Defs); 500d6a0560bSZakk Chen 501e2b7aabbSCraig Topper // Map to keep track of which builtin names have already been emitted. 502e2b7aabbSCraig Topper StringMap<RVVIntrinsic *> BuiltinMap; 503e2b7aabbSCraig Topper 504d6a0560bSZakk Chen OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n"; 505d6a0560bSZakk Chen OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, " 506bfb4c0c3Sjacquesguan "ATTRS, \"zve32x\")\n"; 507d6a0560bSZakk Chen OS << "#endif\n"; 508d6a0560bSZakk Chen for (auto &Def : Defs) { 509e2b7aabbSCraig Topper auto P = 510e2b7aabbSCraig Topper BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); 511e2b7aabbSCraig Topper if (!P.second) { 51223d60ce1SZakk Chen // Verf that this would have produced the same builtin definition. 51323d60ce1SZakk Chen if (P.first->second->hasBuiltinAlias() != Def->hasBuiltinAlias()) 514e2b7aabbSCraig Topper PrintFatalError("Builtin with same name has different hasAutoDef"); 51523d60ce1SZakk Chen else if (!Def->hasBuiltinAlias() && 51623d60ce1SZakk Chen P.first->second->getBuiltinTypeStr() != Def->getBuiltinTypeStr()) 517e2b7aabbSCraig Topper PrintFatalError("Builtin with same name has different type string"); 518e2b7aabbSCraig Topper continue; 519e2b7aabbSCraig Topper } 520e2b7aabbSCraig Topper OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getBuiltinName() << ",\""; 52123d60ce1SZakk Chen if (!Def->hasBuiltinAlias()) 522e2b7aabbSCraig Topper OS << Def->getBuiltinTypeStr(); 523e2b7aabbSCraig Topper OS << "\", \"n\")\n"; 524d6a0560bSZakk Chen } 525d6a0560bSZakk Chen OS << "#undef RISCVV_BUILTIN\n"; 526d6a0560bSZakk Chen } 527d6a0560bSZakk Chen 528d6a0560bSZakk Chen void RVVEmitter::createCodeGen(raw_ostream &OS) { 529d6a0560bSZakk Chen std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 530d6a0560bSZakk Chen createRVVIntrinsics(Defs); 5318f683366SZakk Chen // IR name could be empty, use the stable sort preserves the relative order. 5320e948bfdSRahul Joshi stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A, 533d6a0560bSZakk Chen const std::unique_ptr<RVVIntrinsic> &B) { 53471fd6616SZakk Chen if (A->getIRName() == B->getIRName()) 5351deb6bceSeopXD return (A->getPolicyAttrs() < B->getPolicyAttrs()); 53671fd6616SZakk Chen return (A->getIRName() < B->getIRName()); 537d6a0560bSZakk Chen }); 538e2b7aabbSCraig Topper 539e2b7aabbSCraig Topper // Map to keep track of which builtin names have already been emitted. 540e2b7aabbSCraig Topper StringMap<RVVIntrinsic *> BuiltinMap; 541e2b7aabbSCraig Topper 542239127d7SBrandon Wu // Print switch body when the ir name, ManualCodegen, policy or log2sew 543239127d7SBrandon Wu // changes from previous iteration. 544d6a0560bSZakk Chen RVVIntrinsic *PrevDef = Defs.begin()->get(); 545d6a0560bSZakk Chen for (auto &Def : Defs) { 546d6a0560bSZakk Chen StringRef CurIRName = Def->getIRName(); 5478f683366SZakk Chen if (CurIRName != PrevDef->getIRName() || 54871fd6616SZakk Chen (Def->getManualCodegen() != PrevDef->getManualCodegen()) || 549239127d7SBrandon Wu (Def->getPolicyAttrs() != PrevDef->getPolicyAttrs()) || 550239127d7SBrandon Wu (getSegInstLog2SEW(Def->getOverloadedName()) != 551239127d7SBrandon Wu getSegInstLog2SEW(PrevDef->getOverloadedName()))) { 552f26c41e8SKito Cheng emitCodeGenSwitchBody(PrevDef, OS); 553d6a0560bSZakk Chen } 554d6a0560bSZakk Chen PrevDef = Def.get(); 555e2b7aabbSCraig Topper 556e2b7aabbSCraig Topper auto P = 557e2b7aabbSCraig Topper BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); 558e2b7aabbSCraig Topper if (P.second) { 559e2b7aabbSCraig Topper OS << "case RISCVVector::BI__builtin_rvv_" << Def->getBuiltinName() 560e2b7aabbSCraig Topper << ":\n"; 561e2b7aabbSCraig Topper continue; 562e2b7aabbSCraig Topper } 563e2b7aabbSCraig Topper 564e2b7aabbSCraig Topper if (P.first->second->getIRName() != Def->getIRName()) 565e2b7aabbSCraig Topper PrintFatalError("Builtin with same name has different IRName"); 566e2b7aabbSCraig Topper else if (P.first->second->getManualCodegen() != Def->getManualCodegen()) 567e2b7aabbSCraig Topper PrintFatalError("Builtin with same name has different ManualCodegen"); 56823d60ce1SZakk Chen else if (P.first->second->isMasked() != Def->isMasked()) 56923d60ce1SZakk Chen PrintFatalError("Builtin with same name has different isMasked"); 570e2b7aabbSCraig Topper else if (P.first->second->hasVL() != Def->hasVL()) 57123d60ce1SZakk Chen PrintFatalError("Builtin with same name has different hasVL"); 57223d60ce1SZakk Chen else if (P.first->second->getPolicyScheme() != Def->getPolicyScheme()) 57323d60ce1SZakk Chen PrintFatalError("Builtin with same name has different getPolicyScheme"); 574e2b7aabbSCraig Topper else if (P.first->second->getIntrinsicTypes() != Def->getIntrinsicTypes()) 575e2b7aabbSCraig Topper PrintFatalError("Builtin with same name has different IntrinsicTypes"); 576d6a0560bSZakk Chen } 577f26c41e8SKito Cheng emitCodeGenSwitchBody(Defs.back().get(), OS); 578d6a0560bSZakk Chen OS << "\n"; 579d6a0560bSZakk Chen } 580d6a0560bSZakk Chen 581d6a0560bSZakk Chen void RVVEmitter::createRVVIntrinsics( 5827a5cb15eSKito Cheng std::vector<std::unique_ptr<RVVIntrinsic>> &Out, 5837a5cb15eSKito Cheng std::vector<SemaRecord> *SemaRecords) { 584974fa852SRahul Joshi for (const Record *R : Records.getAllDerivedDefinitions("RVVBuiltin")) { 585d6a0560bSZakk Chen StringRef Name = R->getValueAsString("Name"); 58688c2d4c8SZakk Chen StringRef SuffixProto = R->getValueAsString("Suffix"); 58779e3d57fSZakk Chen StringRef OverloadedName = R->getValueAsString("OverloadedName"); 58879e3d57fSZakk Chen StringRef OverloadedSuffixProto = R->getValueAsString("OverloadedSuffix"); 589d6a0560bSZakk Chen StringRef Prototypes = R->getValueAsString("Prototype"); 590d6a0560bSZakk Chen StringRef TypeRange = R->getValueAsString("TypeRange"); 59123d60ce1SZakk Chen bool HasMasked = R->getValueAsBit("HasMasked"); 592d6a0560bSZakk Chen bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand"); 593d6a0560bSZakk Chen bool HasVL = R->getValueAsBit("HasVL"); 594974fa852SRahul Joshi const Record *MPSRecord = R->getValueAsDef("MaskedPolicyScheme"); 595bc4eef50SZakk Chen auto MaskedPolicyScheme = 596bc4eef50SZakk Chen static_cast<PolicyScheme>(MPSRecord->getValueAsInt("Value")); 597974fa852SRahul Joshi const Record *UMPSRecord = R->getValueAsDef("UnMaskedPolicyScheme"); 598bc4eef50SZakk Chen auto UnMaskedPolicyScheme = 599bc4eef50SZakk Chen static_cast<PolicyScheme>(UMPSRecord->getValueAsInt("Value")); 600d6a0560bSZakk Chen std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL"); 60171fd6616SZakk Chen bool HasTailPolicy = R->getValueAsBit("HasTailPolicy"); 60271fd6616SZakk Chen bool HasMaskPolicy = R->getValueAsBit("HasMaskPolicy"); 60371fd6616SZakk Chen bool SupportOverloading = R->getValueAsBit("SupportOverloading"); 60423d60ce1SZakk Chen bool HasBuiltinAlias = R->getValueAsBit("HasBuiltinAlias"); 60595c0125fSZakk Chen StringRef ManualCodegen = R->getValueAsString("ManualCodegen"); 606d6a0560bSZakk Chen std::vector<int64_t> IntrinsicTypes = 607d6a0560bSZakk Chen R->getValueAsListOfInts("IntrinsicTypes"); 6089ea3dfa5Sjacquesguan std::vector<StringRef> RequiredFeatures = 6099ea3dfa5Sjacquesguan R->getValueAsListOfStrings("RequiredFeatures"); 610d6a0560bSZakk Chen StringRef IRName = R->getValueAsString("IRName"); 61123d60ce1SZakk Chen StringRef MaskedIRName = R->getValueAsString("MaskedIRName"); 612593bf9b4SHsiangkai Wang unsigned NF = R->getValueAsInt("NF"); 6130019226cSeopXD bool IsTuple = R->getValueAsBit("IsTuple"); 61476482078SeopXD bool HasFRMRoundModeOp = R->getValueAsBit("HasFRMRoundModeOp"); 615d6a0560bSZakk Chen 616d94a315eSeopXD const Policy DefaultPolicy; 61762449823SeopXD SmallVector<Policy> SupportedUnMaskedPolicies = 618d94a315eSeopXD RVVIntrinsic::getSupportedUnMaskedPolicies(); 61971fd6616SZakk Chen SmallVector<Policy> SupportedMaskedPolicies = 62071fd6616SZakk Chen RVVIntrinsic::getSupportedMaskedPolicies(HasTailPolicy, HasMaskPolicy); 62171fd6616SZakk Chen 622d6a0560bSZakk Chen // Parse prototype and create a list of primitive type with transformers 6231467e01fSKito Cheng // (operand) in Prototype. Prototype[0] is output operand. 624bc4eef50SZakk Chen SmallVector<PrototypeDescriptor> BasicPrototype = 625bc4eef50SZakk Chen parsePrototypes(Prototypes); 6267ff0bf57SKito Cheng 6271467e01fSKito Cheng SmallVector<PrototypeDescriptor> SuffixDesc = parsePrototypes(SuffixProto); 6281467e01fSKito Cheng SmallVector<PrototypeDescriptor> OverloadedSuffixDesc = 6291467e01fSKito Cheng parsePrototypes(OverloadedSuffixProto); 630d6a0560bSZakk Chen 631d6a0560bSZakk Chen // Compute Builtin types 6326f0d0be5SeopXD auto Prototype = RVVIntrinsic::computeBuiltinTypes( 6336f0d0be5SeopXD BasicPrototype, /*IsMasked=*/false, 6346f0d0be5SeopXD /*HasMaskedOffOperand=*/false, HasVL, NF, UnMaskedPolicyScheme, 6350019226cSeopXD DefaultPolicy, IsTuple); 6360e948bfdSRahul Joshi SmallVector<PrototypeDescriptor> MaskedPrototype; 6371cb38271SeopXD if (HasMasked) 6381cb38271SeopXD MaskedPrototype = RVVIntrinsic::computeBuiltinTypes( 63971fd6616SZakk Chen BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, NF, 6400019226cSeopXD MaskedPolicyScheme, DefaultPolicy, IsTuple); 641d6a0560bSZakk Chen 64295c0125fSZakk Chen // Create Intrinsics for each type and LMUL. 643d6a0560bSZakk Chen for (char I : TypeRange) { 644d6a0560bSZakk Chen for (int Log2LMUL : Log2LMULList) { 6457ff0bf57SKito Cheng BasicType BT = ParseBasicType(I); 6469cf4419eSKazu Hirata std::optional<RVVTypes> Types = 6473fe89be8SKito Cheng TypeCache.computeTypes(BT, Log2LMUL, NF, Prototype); 648d6a0560bSZakk Chen // Ignored to create new intrinsic if there are any illegal types. 649452db157SKazu Hirata if (!Types) 650d6a0560bSZakk Chen continue; 651d6a0560bSZakk Chen 6523fe89be8SKito Cheng auto SuffixStr = 6533fe89be8SKito Cheng RVVIntrinsic::getSuffixStr(TypeCache, BT, Log2LMUL, SuffixDesc); 6543fe89be8SKito Cheng auto OverloadedSuffixStr = RVVIntrinsic::getSuffixStr( 6553fe89be8SKito Cheng TypeCache, BT, Log2LMUL, OverloadedSuffixDesc); 65623d60ce1SZakk Chen // Create a unmasked intrinsic 657d6a0560bSZakk Chen Out.push_back(std::make_unique<RVVIntrinsic>( 6581467e01fSKito Cheng Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName, 65923d60ce1SZakk Chen /*IsMasked=*/false, /*HasMaskedOffOperand=*/false, HasVL, 66071fd6616SZakk Chen UnMaskedPolicyScheme, SupportOverloading, HasBuiltinAlias, 66184741940SCraig Topper ManualCodegen, *Types, IntrinsicTypes, NF, DefaultPolicy, 66284741940SCraig Topper HasFRMRoundModeOp)); 66371fd6616SZakk Chen if (UnMaskedPolicyScheme != PolicyScheme::SchemeNone) 66471fd6616SZakk Chen for (auto P : SupportedUnMaskedPolicies) { 66571fd6616SZakk Chen SmallVector<PrototypeDescriptor> PolicyPrototype = 66671fd6616SZakk Chen RVVIntrinsic::computeBuiltinTypes( 66771fd6616SZakk Chen BasicPrototype, /*IsMasked=*/false, 66871fd6616SZakk Chen /*HasMaskedOffOperand=*/false, HasVL, NF, 6690019226cSeopXD UnMaskedPolicyScheme, P, IsTuple); 6709cf4419eSKazu Hirata std::optional<RVVTypes> PolicyTypes = 6713fe89be8SKito Cheng TypeCache.computeTypes(BT, Log2LMUL, NF, PolicyPrototype); 67271fd6616SZakk Chen Out.push_back(std::make_unique<RVVIntrinsic>( 67371fd6616SZakk Chen Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName, 67471fd6616SZakk Chen /*IsMask=*/false, /*HasMaskedOffOperand=*/false, HasVL, 67571fd6616SZakk Chen UnMaskedPolicyScheme, SupportOverloading, HasBuiltinAlias, 67684741940SCraig Topper ManualCodegen, *PolicyTypes, IntrinsicTypes, NF, P, 67784741940SCraig Topper HasFRMRoundModeOp)); 67871fd6616SZakk Chen } 67971fd6616SZakk Chen if (!HasMasked) 68071fd6616SZakk Chen continue; 68123d60ce1SZakk Chen // Create a masked intrinsic 6829cf4419eSKazu Hirata std::optional<RVVTypes> MaskTypes = 6831ab7e768SeopXD TypeCache.computeTypes(BT, Log2LMUL, NF, MaskedPrototype); 68471fd6616SZakk Chen Out.push_back(std::make_unique<RVVIntrinsic>( 68571fd6616SZakk Chen Name, SuffixStr, OverloadedName, OverloadedSuffixStr, MaskedIRName, 68671fd6616SZakk Chen /*IsMasked=*/true, HasMaskedOffOperand, HasVL, MaskedPolicyScheme, 6876b282294SeopXD SupportOverloading, HasBuiltinAlias, ManualCodegen, *MaskTypes, 68884741940SCraig Topper IntrinsicTypes, NF, DefaultPolicy, HasFRMRoundModeOp)); 68971fd6616SZakk Chen if (MaskedPolicyScheme == PolicyScheme::SchemeNone) 69071fd6616SZakk Chen continue; 69171fd6616SZakk Chen for (auto P : SupportedMaskedPolicies) { 69271fd6616SZakk Chen SmallVector<PrototypeDescriptor> PolicyPrototype = 69371fd6616SZakk Chen RVVIntrinsic::computeBuiltinTypes( 69471fd6616SZakk Chen BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, 6950019226cSeopXD NF, MaskedPolicyScheme, P, IsTuple); 6969cf4419eSKazu Hirata std::optional<RVVTypes> PolicyTypes = 6973fe89be8SKito Cheng TypeCache.computeTypes(BT, Log2LMUL, NF, PolicyPrototype); 698d6a0560bSZakk Chen Out.push_back(std::make_unique<RVVIntrinsic>( 6991467e01fSKito Cheng Name, SuffixStr, OverloadedName, OverloadedSuffixStr, 70071fd6616SZakk Chen MaskedIRName, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, 70171fd6616SZakk Chen MaskedPolicyScheme, SupportOverloading, HasBuiltinAlias, 70284741940SCraig Topper ManualCodegen, *PolicyTypes, IntrinsicTypes, NF, P, 70384741940SCraig Topper HasFRMRoundModeOp)); 704d6a0560bSZakk Chen } 70571fd6616SZakk Chen } // End for Log2LMULList 70671fd6616SZakk Chen } // End for TypeRange 7077a5cb15eSKito Cheng 7087a5cb15eSKito Cheng // We don't emit vsetvli and vsetvlimax for SemaRecord. 7097a5cb15eSKito Cheng // They are written in riscv_vector.td and will emit those marco define in 7107a5cb15eSKito Cheng // riscv_vector.h 7117a5cb15eSKito Cheng if (Name == "vsetvli" || Name == "vsetvlimax") 7127a5cb15eSKito Cheng continue; 7137a5cb15eSKito Cheng 7147a5cb15eSKito Cheng if (!SemaRecords) 7157a5cb15eSKito Cheng continue; 7167a5cb15eSKito Cheng 7177a5cb15eSKito Cheng // Create SemaRecord 7187a5cb15eSKito Cheng SemaRecord SR; 7197a5cb15eSKito Cheng SR.Name = Name.str(); 7207a5cb15eSKito Cheng SR.OverloadedName = OverloadedName.str(); 7217a5cb15eSKito Cheng BasicType TypeRangeMask = BasicType::Unknown; 7227a5cb15eSKito Cheng for (char I : TypeRange) 7237a5cb15eSKito Cheng TypeRangeMask |= ParseBasicType(I); 7247a5cb15eSKito Cheng 7257a5cb15eSKito Cheng SR.TypeRangeMask = static_cast<unsigned>(TypeRangeMask); 7267a5cb15eSKito Cheng 7277a5cb15eSKito Cheng unsigned Log2LMULMask = 0; 7287a5cb15eSKito Cheng for (int Log2LMUL : Log2LMULList) 7297a5cb15eSKito Cheng Log2LMULMask |= 1 << (Log2LMUL + 3); 7307a5cb15eSKito Cheng 7317a5cb15eSKito Cheng SR.Log2LMULMask = Log2LMULMask; 7327a5cb15eSKito Cheng 7337a5cb15eSKito Cheng SR.RequiredExtensions = 0; 7347a5cb15eSKito Cheng for (auto RequiredFeature : RequiredFeatures) { 73509058654SEric Biggers RVVRequire RequireExt = 73609058654SEric Biggers StringSwitch<RVVRequire>(RequiredFeature) 7377a5cb15eSKito Cheng .Case("RV64", RVV_REQ_RV64) 7381e51b359SJim Lin .Case("Zvfhmin", RVV_REQ_Zvfhmin) 739cd5c4cb7SKito Cheng .Case("Xsfvcp", RVV_REQ_Xsfvcp) 74074f38df1SBrandon Wu .Case("Xsfvfnrclipxfqf", RVV_REQ_Xsfvfnrclipxfqf) 741945d2e6eSBrandon Wu .Case("Xsfvfwmaccqqq", RVV_REQ_Xsfvfwmaccqqq) 742d1985e3dSBrandon Wu .Case("Xsfvqmaccdod", RVV_REQ_Xsfvqmaccdod) 743d1985e3dSBrandon Wu .Case("Xsfvqmaccqoq", RVV_REQ_Xsfvqmaccqoq) 7448609819eS4vtomat .Case("Zvbb", RVV_REQ_Zvbb) 7458609819eS4vtomat .Case("Zvbc", RVV_REQ_Zvbc) 7468609819eS4vtomat .Case("Zvkb", RVV_REQ_Zvkb) 7478609819eS4vtomat .Case("Zvkg", RVV_REQ_Zvkg) 7488609819eS4vtomat .Case("Zvkned", RVV_REQ_Zvkned) 7498609819eS4vtomat .Case("Zvknha", RVV_REQ_Zvknha) 75065dc96c2SBrandon Wu .Case("Zvknhb", RVV_REQ_Zvknhb) 7518609819eS4vtomat .Case("Zvksed", RVV_REQ_Zvksed) 7528609819eS4vtomat .Case("Zvksh", RVV_REQ_Zvksh) 753ae5ed2a5SBrandon Wu .Case("Zvfbfwma", RVV_REQ_Zvfbfwma) 7543fa6b9c6SBrandon Wu .Case("Zvfbfmin", RVV_REQ_Zvfbfmin) 75540c2aaf5SBrandon Wu .Case("Zvfh", RVV_REQ_Zvfh) 75609058654SEric Biggers .Case("Experimental", RVV_REQ_Experimental) 7577a5cb15eSKito Cheng .Default(RVV_REQ_None); 7587a5cb15eSKito Cheng assert(RequireExt != RVV_REQ_None && "Unrecognized required feature?"); 7597a5cb15eSKito Cheng SR.RequiredExtensions |= RequireExt; 7607a5cb15eSKito Cheng } 7617a5cb15eSKito Cheng 7627a5cb15eSKito Cheng SR.NF = NF; 76393f8657cSZakk Chen SR.HasMasked = HasMasked; 76493f8657cSZakk Chen SR.HasVL = HasVL; 76593f8657cSZakk Chen SR.HasMaskedOffOperand = HasMaskedOffOperand; 76671fd6616SZakk Chen SR.HasTailPolicy = HasTailPolicy; 76771fd6616SZakk Chen SR.HasMaskPolicy = HasMaskPolicy; 76871fd6616SZakk Chen SR.UnMaskedPolicyScheme = static_cast<uint8_t>(UnMaskedPolicyScheme); 76971fd6616SZakk Chen SR.MaskedPolicyScheme = static_cast<uint8_t>(MaskedPolicyScheme); 77093f8657cSZakk Chen SR.Prototype = std::move(BasicPrototype); 7717a5cb15eSKito Cheng SR.Suffix = parsePrototypes(SuffixProto); 7727a5cb15eSKito Cheng SR.OverloadedSuffix = parsePrototypes(OverloadedSuffixProto); 7730019226cSeopXD SR.IsTuple = IsTuple; 77476482078SeopXD SR.HasFRMRoundModeOp = HasFRMRoundModeOp; 7757a5cb15eSKito Cheng 7767a5cb15eSKito Cheng SemaRecords->push_back(SR); 777d6a0560bSZakk Chen } 778d6a0560bSZakk Chen } 779d6a0560bSZakk Chen 78023d60ce1SZakk Chen void RVVEmitter::printHeaderCode(raw_ostream &OS) { 781974fa852SRahul Joshi for (const Record *R : Records.getAllDerivedDefinitions("RVVHeader")) { 7825158cfefSHsiangkai Wang StringRef HeaderCodeStr = R->getValueAsString("HeaderCode"); 7835158cfefSHsiangkai Wang OS << HeaderCodeStr.str(); 7845158cfefSHsiangkai Wang } 7855158cfefSHsiangkai Wang } 7865158cfefSHsiangkai Wang 7877a5cb15eSKito Cheng void RVVEmitter::createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out, 7887a5cb15eSKito Cheng SemaSignatureTable &SST, 7897a5cb15eSKito Cheng ArrayRef<SemaRecord> SemaRecords) { 7907a5cb15eSKito Cheng SST.init(SemaRecords); 7917a5cb15eSKito Cheng 7927a5cb15eSKito Cheng for (const auto &SR : SemaRecords) { 7937a5cb15eSKito Cheng Out.emplace_back(RVVIntrinsicRecord()); 7947a5cb15eSKito Cheng RVVIntrinsicRecord &R = Out.back(); 7957a5cb15eSKito Cheng R.Name = SR.Name.c_str(); 7967a5cb15eSKito Cheng R.OverloadedName = SR.OverloadedName.c_str(); 7977a5cb15eSKito Cheng R.PrototypeIndex = SST.getIndex(SR.Prototype); 7987a5cb15eSKito Cheng R.SuffixIndex = SST.getIndex(SR.Suffix); 7997a5cb15eSKito Cheng R.OverloadedSuffixIndex = SST.getIndex(SR.OverloadedSuffix); 8007a5cb15eSKito Cheng R.PrototypeLength = SR.Prototype.size(); 8017a5cb15eSKito Cheng R.SuffixLength = SR.Suffix.size(); 8027a5cb15eSKito Cheng R.OverloadedSuffixSize = SR.OverloadedSuffix.size(); 8037a5cb15eSKito Cheng R.RequiredExtensions = SR.RequiredExtensions; 8047a5cb15eSKito Cheng R.TypeRangeMask = SR.TypeRangeMask; 8057a5cb15eSKito Cheng R.Log2LMULMask = SR.Log2LMULMask; 8067a5cb15eSKito Cheng R.NF = SR.NF; 80793f8657cSZakk Chen R.HasMasked = SR.HasMasked; 80893f8657cSZakk Chen R.HasVL = SR.HasVL; 80993f8657cSZakk Chen R.HasMaskedOffOperand = SR.HasMaskedOffOperand; 81071fd6616SZakk Chen R.HasTailPolicy = SR.HasTailPolicy; 81171fd6616SZakk Chen R.HasMaskPolicy = SR.HasMaskPolicy; 81271fd6616SZakk Chen R.UnMaskedPolicyScheme = SR.UnMaskedPolicyScheme; 81371fd6616SZakk Chen R.MaskedPolicyScheme = SR.MaskedPolicyScheme; 8140019226cSeopXD R.IsTuple = SR.IsTuple; 81576482078SeopXD R.HasFRMRoundModeOp = SR.HasFRMRoundModeOp; 8167a5cb15eSKito Cheng 8177a5cb15eSKito Cheng assert(R.PrototypeIndex != 8187a5cb15eSKito Cheng static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 8197a5cb15eSKito Cheng assert(R.SuffixIndex != 8207a5cb15eSKito Cheng static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 8217a5cb15eSKito Cheng assert(R.OverloadedSuffixIndex != 8227a5cb15eSKito Cheng static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 823d6a0560bSZakk Chen } 824d6a0560bSZakk Chen } 825d6a0560bSZakk Chen 8267a5cb15eSKito Cheng void RVVEmitter::createSema(raw_ostream &OS) { 8277a5cb15eSKito Cheng std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 8287a5cb15eSKito Cheng std::vector<RVVIntrinsicRecord> RVVIntrinsicRecords; 8297a5cb15eSKito Cheng SemaSignatureTable SST; 8307a5cb15eSKito Cheng std::vector<SemaRecord> SemaRecords; 8317a5cb15eSKito Cheng 8327a5cb15eSKito Cheng createRVVIntrinsics(Defs, &SemaRecords); 8337a5cb15eSKito Cheng 8347a5cb15eSKito Cheng createRVVIntrinsicRecords(RVVIntrinsicRecords, SST, SemaRecords); 8357a5cb15eSKito Cheng 8367a5cb15eSKito Cheng // Emit signature table for SemaRISCVVectorLookup.cpp. 8377a5cb15eSKito Cheng OS << "#ifdef DECL_SIGNATURE_TABLE\n"; 8387a5cb15eSKito Cheng SST.print(OS); 8397a5cb15eSKito Cheng OS << "#endif\n"; 8407a5cb15eSKito Cheng 8417a5cb15eSKito Cheng // Emit RVVIntrinsicRecords for SemaRISCVVectorLookup.cpp. 8427a5cb15eSKito Cheng OS << "#ifdef DECL_INTRINSIC_RECORDS\n"; 8437a5cb15eSKito Cheng for (const RVVIntrinsicRecord &Record : RVVIntrinsicRecords) 8447a5cb15eSKito Cheng OS << Record; 8457a5cb15eSKito Cheng OS << "#endif\n"; 846d6a0560bSZakk Chen } 847d6a0560bSZakk Chen 848d6a0560bSZakk Chen namespace clang { 849974fa852SRahul Joshi void EmitRVVHeader(const RecordKeeper &Records, raw_ostream &OS) { 850d6a0560bSZakk Chen RVVEmitter(Records).createHeader(OS); 851d6a0560bSZakk Chen } 852d6a0560bSZakk Chen 853974fa852SRahul Joshi void EmitRVVBuiltins(const RecordKeeper &Records, raw_ostream &OS) { 854d6a0560bSZakk Chen RVVEmitter(Records).createBuiltins(OS); 855d6a0560bSZakk Chen } 856d6a0560bSZakk Chen 857974fa852SRahul Joshi void EmitRVVBuiltinCG(const RecordKeeper &Records, raw_ostream &OS) { 858d6a0560bSZakk Chen RVVEmitter(Records).createCodeGen(OS); 859d6a0560bSZakk Chen } 860d6a0560bSZakk Chen 861974fa852SRahul Joshi void EmitRVVBuiltinSema(const RecordKeeper &Records, raw_ostream &OS) { 8627a5cb15eSKito Cheng RVVEmitter(Records).createSema(OS); 8637a5cb15eSKito Cheng } 8647a5cb15eSKito Cheng 865d6a0560bSZakk Chen } // End namespace clang 866