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 1781ad6265SDimitry Andric #include "clang/Support/RISCVVIntrinsicUtils.h" 18fe6060f1SDimitry Andric #include "llvm/ADT/ArrayRef.h" 19fe6060f1SDimitry Andric #include "llvm/ADT/SmallSet.h" 20fe6060f1SDimitry Andric #include "llvm/ADT/StringExtras.h" 21fe6060f1SDimitry Andric #include "llvm/ADT/StringMap.h" 22fe6060f1SDimitry Andric #include "llvm/ADT/StringSet.h" 23972a253aSDimitry Andric #include "llvm/ADT/StringSwitch.h" 24fe6060f1SDimitry Andric #include "llvm/ADT/Twine.h" 25fe6060f1SDimitry Andric #include "llvm/TableGen/Error.h" 26fe6060f1SDimitry Andric #include "llvm/TableGen/Record.h" 27fe6060f1SDimitry Andric #include <numeric> 28bdd1243dSDimitry Andric #include <optional> 29fe6060f1SDimitry Andric 30fe6060f1SDimitry Andric using namespace llvm; 3181ad6265SDimitry Andric using namespace clang::RISCV; 32fe6060f1SDimitry Andric 33fe6060f1SDimitry Andric namespace { 34972a253aSDimitry Andric struct SemaRecord { 35972a253aSDimitry Andric // Intrinsic name, e.g. vadd_vv 36972a253aSDimitry Andric std::string Name; 37972a253aSDimitry Andric 38972a253aSDimitry Andric // Overloaded intrinsic name, could be empty if can be computed from Name 39972a253aSDimitry Andric // e.g. vadd 40972a253aSDimitry Andric std::string OverloadedName; 41972a253aSDimitry Andric 42972a253aSDimitry Andric // Supported type, mask of BasicType. 43972a253aSDimitry Andric unsigned TypeRangeMask; 44972a253aSDimitry Andric 45972a253aSDimitry Andric // Supported LMUL. 46972a253aSDimitry Andric unsigned Log2LMULMask; 47972a253aSDimitry Andric 48972a253aSDimitry Andric // Required extensions for this intrinsic. 49cb14a3feSDimitry Andric uint32_t RequiredExtensions; 50972a253aSDimitry Andric 51972a253aSDimitry Andric // Prototype for this intrinsic. 52972a253aSDimitry Andric SmallVector<PrototypeDescriptor> Prototype; 53972a253aSDimitry Andric 54972a253aSDimitry Andric // Suffix of intrinsic name. 55972a253aSDimitry Andric SmallVector<PrototypeDescriptor> Suffix; 56972a253aSDimitry Andric 57972a253aSDimitry Andric // Suffix of overloaded intrinsic name. 58972a253aSDimitry Andric SmallVector<PrototypeDescriptor> OverloadedSuffix; 59972a253aSDimitry Andric 60972a253aSDimitry Andric // Number of field, large than 1 if it's segment load/store. 61972a253aSDimitry Andric unsigned NF; 62972a253aSDimitry Andric 63972a253aSDimitry Andric bool HasMasked :1; 64972a253aSDimitry Andric bool HasVL :1; 65972a253aSDimitry Andric bool HasMaskedOffOperand :1; 66bdd1243dSDimitry Andric bool HasTailPolicy : 1; 67bdd1243dSDimitry Andric bool HasMaskPolicy : 1; 6806c3fb27SDimitry Andric bool HasFRMRoundModeOp : 1; 6906c3fb27SDimitry Andric bool IsTuple : 1; 70*0fca6ea1SDimitry Andric LLVM_PREFERRED_TYPE(PolicyScheme) 71bdd1243dSDimitry Andric uint8_t UnMaskedPolicyScheme : 2; 72*0fca6ea1SDimitry Andric LLVM_PREFERRED_TYPE(PolicyScheme) 73bdd1243dSDimitry Andric uint8_t MaskedPolicyScheme : 2; 74972a253aSDimitry Andric }; 75972a253aSDimitry Andric 76972a253aSDimitry Andric // Compressed function signature table. 77972a253aSDimitry Andric class SemaSignatureTable { 78972a253aSDimitry Andric private: 79972a253aSDimitry Andric std::vector<PrototypeDescriptor> SignatureTable; 80972a253aSDimitry Andric 81972a253aSDimitry Andric void insert(ArrayRef<PrototypeDescriptor> Signature); 82972a253aSDimitry Andric 83972a253aSDimitry Andric public: 84972a253aSDimitry Andric static constexpr unsigned INVALID_INDEX = ~0U; 85972a253aSDimitry Andric 86972a253aSDimitry Andric // Create compressed signature table from SemaRecords. 87972a253aSDimitry Andric void init(ArrayRef<SemaRecord> SemaRecords); 88972a253aSDimitry Andric 89972a253aSDimitry Andric // Query the Signature, return INVALID_INDEX if not found. 90972a253aSDimitry Andric unsigned getIndex(ArrayRef<PrototypeDescriptor> Signature); 91972a253aSDimitry Andric 92972a253aSDimitry Andric /// Print signature table in RVVHeader Record to \p OS 93972a253aSDimitry Andric void print(raw_ostream &OS); 94972a253aSDimitry Andric }; 95972a253aSDimitry Andric 96fe6060f1SDimitry Andric class RVVEmitter { 97fe6060f1SDimitry Andric private: 98fe6060f1SDimitry Andric RecordKeeper &Records; 99bdd1243dSDimitry Andric RVVTypeCache TypeCache; 100fe6060f1SDimitry Andric 101fe6060f1SDimitry Andric public: 102fe6060f1SDimitry Andric RVVEmitter(RecordKeeper &R) : Records(R) {} 103fe6060f1SDimitry Andric 104fe6060f1SDimitry Andric /// Emit riscv_vector.h 105fe6060f1SDimitry Andric void createHeader(raw_ostream &o); 106fe6060f1SDimitry Andric 107fe6060f1SDimitry Andric /// Emit all the __builtin prototypes and code needed by Sema. 108fe6060f1SDimitry Andric void createBuiltins(raw_ostream &o); 109fe6060f1SDimitry Andric 110fe6060f1SDimitry Andric /// Emit all the information needed to map builtin -> LLVM IR intrinsic. 111fe6060f1SDimitry Andric void createCodeGen(raw_ostream &o); 112fe6060f1SDimitry Andric 113972a253aSDimitry Andric /// Emit all the information needed by SemaRISCVVectorLookup.cpp. 114972a253aSDimitry Andric /// We've large number of intrinsic function for RVV, creating a customized 115972a253aSDimitry Andric /// could speed up the compilation time. 116972a253aSDimitry Andric void createSema(raw_ostream &o); 117972a253aSDimitry Andric 118fe6060f1SDimitry Andric private: 119972a253aSDimitry Andric /// Create all intrinsics and add them to \p Out and SemaRecords. 120972a253aSDimitry Andric void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out, 121972a253aSDimitry Andric std::vector<SemaRecord> *SemaRecords = nullptr); 122972a253aSDimitry Andric /// Create all intrinsic records and SemaSignatureTable from SemaRecords. 123972a253aSDimitry Andric void createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out, 124972a253aSDimitry Andric SemaSignatureTable &SST, 125972a253aSDimitry Andric ArrayRef<SemaRecord> SemaRecords); 126972a253aSDimitry Andric 12781ad6265SDimitry Andric /// Print HeaderCode in RVVHeader Record to \p Out 12881ad6265SDimitry Andric void printHeaderCode(raw_ostream &OS); 129fe6060f1SDimitry Andric }; 130fe6060f1SDimitry Andric 131fe6060f1SDimitry Andric } // namespace 132fe6060f1SDimitry Andric 13381ad6265SDimitry Andric static BasicType ParseBasicType(char c) { 13481ad6265SDimitry Andric switch (c) { 135fe6060f1SDimitry Andric case 'c': 13681ad6265SDimitry Andric return BasicType::Int8; 137fe6060f1SDimitry Andric break; 138fe6060f1SDimitry Andric case 's': 13981ad6265SDimitry Andric return BasicType::Int16; 140fe6060f1SDimitry Andric break; 141fe6060f1SDimitry Andric case 'i': 14281ad6265SDimitry Andric return BasicType::Int32; 143fe6060f1SDimitry Andric break; 144fe6060f1SDimitry Andric case 'l': 14581ad6265SDimitry Andric return BasicType::Int64; 146fe6060f1SDimitry Andric break; 147fe6060f1SDimitry Andric case 'x': 14881ad6265SDimitry Andric return BasicType::Float16; 149fe6060f1SDimitry Andric break; 150fe6060f1SDimitry Andric case 'f': 15181ad6265SDimitry Andric return BasicType::Float32; 152fe6060f1SDimitry Andric break; 153fe6060f1SDimitry Andric case 'd': 15481ad6265SDimitry Andric return BasicType::Float64; 155fe6060f1SDimitry Andric break; 156647cbc5dSDimitry Andric case 'y': 1575f757f3fSDimitry Andric return BasicType::BFloat16; 1585f757f3fSDimitry Andric break; 159fe6060f1SDimitry Andric default: 16081ad6265SDimitry Andric return BasicType::Unknown; 161fe6060f1SDimitry Andric } 162fe6060f1SDimitry Andric } 163fe6060f1SDimitry Andric 16406c3fb27SDimitry Andric static VectorTypeModifier getTupleVTM(unsigned NF) { 16506c3fb27SDimitry Andric assert(2 <= NF && NF <= 8 && "2 <= NF <= 8"); 16606c3fb27SDimitry Andric return static_cast<VectorTypeModifier>( 16706c3fb27SDimitry Andric static_cast<uint8_t>(VectorTypeModifier::Tuple2) + (NF - 2)); 16806c3fb27SDimitry Andric } 16906c3fb27SDimitry Andric 17081ad6265SDimitry Andric void emitCodeGenSwitchBody(const RVVIntrinsic *RVVI, raw_ostream &OS) { 17181ad6265SDimitry Andric if (!RVVI->getIRName().empty()) 17281ad6265SDimitry Andric OS << " ID = Intrinsic::riscv_" + RVVI->getIRName() + ";\n"; 17381ad6265SDimitry Andric if (RVVI->getNF() >= 2) 17481ad6265SDimitry Andric OS << " NF = " + utostr(RVVI->getNF()) + ";\n"; 175bdd1243dSDimitry Andric 176bdd1243dSDimitry Andric OS << " PolicyAttrs = " << RVVI->getPolicyAttrsBits() << ";\n"; 177bdd1243dSDimitry Andric 17881ad6265SDimitry Andric if (RVVI->hasManualCodegen()) { 179bdd1243dSDimitry Andric OS << "IsMasked = " << (RVVI->isMasked() ? "true" : "false") << ";\n"; 18081ad6265SDimitry Andric OS << RVVI->getManualCodegen(); 181fe6060f1SDimitry Andric OS << "break;\n"; 182fe6060f1SDimitry Andric return; 183fe6060f1SDimitry Andric } 184fe6060f1SDimitry Andric 185753f127fSDimitry Andric for (const auto &I : enumerate(RVVI->getInputTypes())) { 186753f127fSDimitry Andric if (I.value()->isPointer()) { 187753f127fSDimitry Andric assert(RVVI->getIntrinsicTypes().front() == -1 && 188753f127fSDimitry Andric "RVVI should be vector load intrinsic."); 189753f127fSDimitry Andric } 190753f127fSDimitry Andric } 191753f127fSDimitry Andric 19281ad6265SDimitry Andric if (RVVI->isMasked()) { 19381ad6265SDimitry Andric if (RVVI->hasVL()) { 194fe6060f1SDimitry Andric OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n"; 19581ad6265SDimitry Andric if (RVVI->hasPolicyOperand()) 196349cc55cSDimitry Andric OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType()," 197bdd1243dSDimitry Andric " PolicyAttrs));\n"; 198bdd1243dSDimitry Andric if (RVVI->hasMaskedOffOperand() && RVVI->getPolicyAttrs().isTAMAPolicy()) 199bdd1243dSDimitry Andric OS << " Ops.insert(Ops.begin(), " 200bdd1243dSDimitry Andric "llvm::PoisonValue::get(ResultType));\n"; 201bdd1243dSDimitry Andric // Masked reduction cases. 202bdd1243dSDimitry Andric if (!RVVI->hasMaskedOffOperand() && RVVI->hasPassthruOperand() && 203bdd1243dSDimitry Andric RVVI->getPolicyAttrs().isTAMAPolicy()) 204bdd1243dSDimitry Andric OS << " Ops.insert(Ops.begin(), " 205bdd1243dSDimitry Andric "llvm::PoisonValue::get(ResultType));\n"; 206fe6060f1SDimitry Andric } else { 207fe6060f1SDimitry Andric OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n"; 208fe6060f1SDimitry Andric } 20981ad6265SDimitry Andric } else { 21081ad6265SDimitry Andric if (RVVI->hasPolicyOperand()) 21181ad6265SDimitry Andric OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(), " 212bdd1243dSDimitry Andric "PolicyAttrs));\n"; 213bdd1243dSDimitry Andric else if (RVVI->hasPassthruOperand() && RVVI->getPolicyAttrs().isTAPolicy()) 214bdd1243dSDimitry Andric OS << " Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));\n"; 215fe6060f1SDimitry Andric } 216fe6060f1SDimitry Andric 217fe6060f1SDimitry Andric OS << " IntrinsicTypes = {"; 218fe6060f1SDimitry Andric ListSeparator LS; 21981ad6265SDimitry Andric for (const auto &Idx : RVVI->getIntrinsicTypes()) { 220fe6060f1SDimitry Andric if (Idx == -1) 221fe6060f1SDimitry Andric OS << LS << "ResultType"; 222fe6060f1SDimitry Andric else 223fe6060f1SDimitry Andric OS << LS << "Ops[" << Idx << "]->getType()"; 224fe6060f1SDimitry Andric } 225fe6060f1SDimitry Andric 226fe6060f1SDimitry Andric // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is 227fe6060f1SDimitry Andric // always last operand. 22881ad6265SDimitry Andric if (RVVI->hasVL()) 229fe6060f1SDimitry Andric OS << ", Ops.back()->getType()"; 230fe6060f1SDimitry Andric OS << "};\n"; 231fe6060f1SDimitry Andric OS << " break;\n"; 232fe6060f1SDimitry Andric } 233fe6060f1SDimitry Andric 234972a253aSDimitry Andric //===----------------------------------------------------------------------===// 235972a253aSDimitry Andric // SemaSignatureTable implementation 236972a253aSDimitry Andric //===----------------------------------------------------------------------===// 237972a253aSDimitry Andric void SemaSignatureTable::init(ArrayRef<SemaRecord> SemaRecords) { 238972a253aSDimitry Andric // Sort signature entries by length, let longer signature insert first, to 239972a253aSDimitry Andric // make it more possible to reuse table entries, that can reduce ~10% table 240972a253aSDimitry Andric // size. 241972a253aSDimitry Andric struct Compare { 242972a253aSDimitry Andric bool operator()(const SmallVector<PrototypeDescriptor> &A, 243972a253aSDimitry Andric const SmallVector<PrototypeDescriptor> &B) const { 244972a253aSDimitry Andric if (A.size() != B.size()) 245972a253aSDimitry Andric return A.size() > B.size(); 246972a253aSDimitry Andric 247972a253aSDimitry Andric size_t Len = A.size(); 248972a253aSDimitry Andric for (size_t i = 0; i < Len; ++i) { 249972a253aSDimitry Andric if (A[i] != B[i]) 250972a253aSDimitry Andric return A[i] < B[i]; 251fe6060f1SDimitry Andric } 252fe6060f1SDimitry Andric 253972a253aSDimitry Andric return false; 254fe6060f1SDimitry Andric } 255972a253aSDimitry Andric }; 256972a253aSDimitry Andric 257972a253aSDimitry Andric std::set<SmallVector<PrototypeDescriptor>, Compare> Signatures; 258972a253aSDimitry Andric auto InsertToSignatureSet = 259972a253aSDimitry Andric [&](const SmallVector<PrototypeDescriptor> &Signature) { 260972a253aSDimitry Andric if (Signature.empty()) 261972a253aSDimitry Andric return; 262972a253aSDimitry Andric 263972a253aSDimitry Andric Signatures.insert(Signature); 264972a253aSDimitry Andric }; 265972a253aSDimitry Andric 266972a253aSDimitry Andric assert(!SemaRecords.empty()); 267972a253aSDimitry Andric 2685f757f3fSDimitry Andric for (const SemaRecord &SR : SemaRecords) { 269972a253aSDimitry Andric InsertToSignatureSet(SR.Prototype); 270972a253aSDimitry Andric InsertToSignatureSet(SR.Suffix); 271972a253aSDimitry Andric InsertToSignatureSet(SR.OverloadedSuffix); 2725f757f3fSDimitry Andric } 273972a253aSDimitry Andric 2745f757f3fSDimitry Andric for (auto &Sig : Signatures) 2755f757f3fSDimitry Andric insert(Sig); 276972a253aSDimitry Andric } 277972a253aSDimitry Andric 278972a253aSDimitry Andric void SemaSignatureTable::insert(ArrayRef<PrototypeDescriptor> Signature) { 279972a253aSDimitry Andric if (getIndex(Signature) != INVALID_INDEX) 280972a253aSDimitry Andric return; 281972a253aSDimitry Andric 282972a253aSDimitry Andric // Insert Signature into SignatureTable if not found in the table. 283972a253aSDimitry Andric SignatureTable.insert(SignatureTable.begin(), Signature.begin(), 284972a253aSDimitry Andric Signature.end()); 285972a253aSDimitry Andric } 286972a253aSDimitry Andric 287972a253aSDimitry Andric unsigned SemaSignatureTable::getIndex(ArrayRef<PrototypeDescriptor> Signature) { 288972a253aSDimitry Andric // Empty signature could be point into any index since there is length 289972a253aSDimitry Andric // field when we use, so just always point it to 0. 290972a253aSDimitry Andric if (Signature.empty()) 291972a253aSDimitry Andric return 0; 292972a253aSDimitry Andric 293972a253aSDimitry Andric // Checking Signature already in table or not. 2945f757f3fSDimitry Andric if (Signature.size() <= SignatureTable.size()) { 295972a253aSDimitry Andric size_t Bound = SignatureTable.size() - Signature.size() + 1; 296972a253aSDimitry Andric for (size_t Index = 0; Index < Bound; ++Index) { 297972a253aSDimitry Andric if (equal(Signature.begin(), Signature.end(), 298972a253aSDimitry Andric SignatureTable.begin() + Index)) 299972a253aSDimitry Andric return Index; 300972a253aSDimitry Andric } 301972a253aSDimitry Andric } 302972a253aSDimitry Andric 303972a253aSDimitry Andric return INVALID_INDEX; 304972a253aSDimitry Andric } 305972a253aSDimitry Andric 306972a253aSDimitry Andric void SemaSignatureTable::print(raw_ostream &OS) { 307972a253aSDimitry Andric for (const auto &Sig : SignatureTable) 308972a253aSDimitry Andric OS << "PrototypeDescriptor(" << static_cast<int>(Sig.PT) << ", " 309972a253aSDimitry Andric << static_cast<int>(Sig.VTM) << ", " << static_cast<int>(Sig.TM) 310972a253aSDimitry Andric << "),\n"; 311fe6060f1SDimitry Andric } 312fe6060f1SDimitry Andric 313fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 314fe6060f1SDimitry Andric // RVVEmitter implementation 315fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 316fe6060f1SDimitry Andric void RVVEmitter::createHeader(raw_ostream &OS) { 317fe6060f1SDimitry Andric 318fe6060f1SDimitry Andric OS << "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics " 319fe6060f1SDimitry Andric "-------------------===\n" 320fe6060f1SDimitry Andric " *\n" 321fe6060f1SDimitry Andric " *\n" 322fe6060f1SDimitry Andric " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " 323fe6060f1SDimitry Andric "Exceptions.\n" 324fe6060f1SDimitry Andric " * See https://llvm.org/LICENSE.txt for license information.\n" 325fe6060f1SDimitry Andric " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 326fe6060f1SDimitry Andric " *\n" 327fe6060f1SDimitry Andric " *===-----------------------------------------------------------------" 328fe6060f1SDimitry Andric "------===\n" 329fe6060f1SDimitry Andric " */\n\n"; 330fe6060f1SDimitry Andric 331fe6060f1SDimitry Andric OS << "#ifndef __RISCV_VECTOR_H\n"; 332fe6060f1SDimitry Andric OS << "#define __RISCV_VECTOR_H\n\n"; 333fe6060f1SDimitry Andric 334fe6060f1SDimitry Andric OS << "#include <stdint.h>\n"; 335fe6060f1SDimitry Andric OS << "#include <stddef.h>\n\n"; 336fe6060f1SDimitry Andric 337fe6060f1SDimitry Andric OS << "#ifdef __cplusplus\n"; 338fe6060f1SDimitry Andric OS << "extern \"C\" {\n"; 339fe6060f1SDimitry Andric OS << "#endif\n\n"; 340fe6060f1SDimitry Andric 341972a253aSDimitry Andric OS << "#pragma clang riscv intrinsic vector\n\n"; 342349cc55cSDimitry Andric 343972a253aSDimitry Andric printHeaderCode(OS); 344fe6060f1SDimitry Andric 345fe6060f1SDimitry Andric auto printType = [&](auto T) { 346fe6060f1SDimitry Andric OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr() 347fe6060f1SDimitry Andric << ";\n"; 348fe6060f1SDimitry Andric }; 349fe6060f1SDimitry Andric 350fe6060f1SDimitry Andric constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3}; 351fe6060f1SDimitry Andric // Print RVV boolean types. 352fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 353bdd1243dSDimitry Andric auto T = TypeCache.computeType(BasicType::Int8, Log2LMUL, 35481ad6265SDimitry Andric PrototypeDescriptor::Mask); 35581ad6265SDimitry Andric if (T) 356bdd1243dSDimitry Andric printType(*T); 357fe6060f1SDimitry Andric } 358fe6060f1SDimitry Andric // Print RVV int/float types. 359fe6060f1SDimitry Andric for (char I : StringRef("csil")) { 36081ad6265SDimitry Andric BasicType BT = ParseBasicType(I); 361fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 362bdd1243dSDimitry Andric auto T = TypeCache.computeType(BT, Log2LMUL, PrototypeDescriptor::Vector); 36381ad6265SDimitry Andric if (T) { 364bdd1243dSDimitry Andric printType(*T); 365bdd1243dSDimitry Andric auto UT = TypeCache.computeType( 36681ad6265SDimitry Andric BT, Log2LMUL, 36781ad6265SDimitry Andric PrototypeDescriptor(BaseTypeModifier::Vector, 36881ad6265SDimitry Andric VectorTypeModifier::NoModifier, 36981ad6265SDimitry Andric TypeModifier::UnsignedInteger)); 370bdd1243dSDimitry Andric printType(*UT); 371fe6060f1SDimitry Andric } 37206c3fb27SDimitry Andric for (int NF = 2; NF <= 8; ++NF) { 37306c3fb27SDimitry Andric auto TupleT = TypeCache.computeType( 37406c3fb27SDimitry Andric BT, Log2LMUL, 37506c3fb27SDimitry Andric PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF), 37606c3fb27SDimitry Andric TypeModifier::SignedInteger)); 37706c3fb27SDimitry Andric auto TupleUT = TypeCache.computeType( 37806c3fb27SDimitry Andric BT, Log2LMUL, 37906c3fb27SDimitry Andric PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF), 38006c3fb27SDimitry Andric TypeModifier::UnsignedInteger)); 38106c3fb27SDimitry Andric if (TupleT) 38206c3fb27SDimitry Andric printType(*TupleT); 38306c3fb27SDimitry Andric if (TupleUT) 38406c3fb27SDimitry Andric printType(*TupleUT); 385fe6060f1SDimitry Andric } 386fe6060f1SDimitry Andric } 387fe6060f1SDimitry Andric } 388fe6060f1SDimitry Andric 3895f757f3fSDimitry Andric for (BasicType BT : {BasicType::Float16, BasicType::Float32, 3905f757f3fSDimitry Andric BasicType::Float64, BasicType::BFloat16}) { 391fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 39206c3fb27SDimitry Andric auto T = TypeCache.computeType(BT, Log2LMUL, PrototypeDescriptor::Vector); 39381ad6265SDimitry Andric if (T) 394bdd1243dSDimitry Andric printType(*T); 39506c3fb27SDimitry Andric for (int NF = 2; NF <= 8; ++NF) { 39606c3fb27SDimitry Andric auto TupleT = TypeCache.computeType( 39706c3fb27SDimitry Andric BT, Log2LMUL, 39806c3fb27SDimitry Andric PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF), 3995f757f3fSDimitry Andric (BT == BasicType::BFloat16 4005f757f3fSDimitry Andric ? TypeModifier::BFloat 4015f757f3fSDimitry Andric : TypeModifier::Float))); 40206c3fb27SDimitry Andric if (TupleT) 40306c3fb27SDimitry Andric printType(*TupleT); 404fe6060f1SDimitry Andric } 405fe6060f1SDimitry Andric } 40606c3fb27SDimitry Andric } 407fe6060f1SDimitry Andric 408fe6060f1SDimitry Andric OS << "#define __riscv_v_intrinsic_overloading 1\n"; 409fe6060f1SDimitry Andric 410fe6060f1SDimitry Andric OS << "\n#ifdef __cplusplus\n"; 411fe6060f1SDimitry Andric OS << "}\n"; 412349cc55cSDimitry Andric OS << "#endif // __cplusplus\n"; 413fe6060f1SDimitry Andric OS << "#endif // __RISCV_VECTOR_H\n"; 414fe6060f1SDimitry Andric } 415fe6060f1SDimitry Andric 416fe6060f1SDimitry Andric void RVVEmitter::createBuiltins(raw_ostream &OS) { 417fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 418fe6060f1SDimitry Andric createRVVIntrinsics(Defs); 419fe6060f1SDimitry Andric 420349cc55cSDimitry Andric // Map to keep track of which builtin names have already been emitted. 421349cc55cSDimitry Andric StringMap<RVVIntrinsic *> BuiltinMap; 422349cc55cSDimitry Andric 423fe6060f1SDimitry Andric OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n"; 424fe6060f1SDimitry Andric OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, " 42581ad6265SDimitry Andric "ATTRS, \"zve32x\")\n"; 426fe6060f1SDimitry Andric OS << "#endif\n"; 427fe6060f1SDimitry Andric for (auto &Def : Defs) { 428349cc55cSDimitry Andric auto P = 429349cc55cSDimitry Andric BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); 430349cc55cSDimitry Andric if (!P.second) { 43181ad6265SDimitry Andric // Verf that this would have produced the same builtin definition. 43281ad6265SDimitry Andric if (P.first->second->hasBuiltinAlias() != Def->hasBuiltinAlias()) 433349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different hasAutoDef"); 43481ad6265SDimitry Andric else if (!Def->hasBuiltinAlias() && 43581ad6265SDimitry Andric P.first->second->getBuiltinTypeStr() != Def->getBuiltinTypeStr()) 436349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different type string"); 437349cc55cSDimitry Andric continue; 438349cc55cSDimitry Andric } 439349cc55cSDimitry Andric OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getBuiltinName() << ",\""; 44081ad6265SDimitry Andric if (!Def->hasBuiltinAlias()) 441349cc55cSDimitry Andric OS << Def->getBuiltinTypeStr(); 442349cc55cSDimitry Andric OS << "\", \"n\")\n"; 443fe6060f1SDimitry Andric } 444fe6060f1SDimitry Andric OS << "#undef RISCVV_BUILTIN\n"; 445fe6060f1SDimitry Andric } 446fe6060f1SDimitry Andric 447fe6060f1SDimitry Andric void RVVEmitter::createCodeGen(raw_ostream &OS) { 448fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 449fe6060f1SDimitry Andric createRVVIntrinsics(Defs); 450fe6060f1SDimitry Andric // IR name could be empty, use the stable sort preserves the relative order. 451349cc55cSDimitry Andric llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A, 452fe6060f1SDimitry Andric const std::unique_ptr<RVVIntrinsic> &B) { 453bdd1243dSDimitry Andric if (A->getIRName() == B->getIRName()) 454bdd1243dSDimitry Andric return (A->getPolicyAttrs() < B->getPolicyAttrs()); 455bdd1243dSDimitry Andric return (A->getIRName() < B->getIRName()); 456fe6060f1SDimitry Andric }); 457349cc55cSDimitry Andric 458349cc55cSDimitry Andric // Map to keep track of which builtin names have already been emitted. 459349cc55cSDimitry Andric StringMap<RVVIntrinsic *> BuiltinMap; 460349cc55cSDimitry Andric 461bdd1243dSDimitry Andric // Print switch body when the ir name, ManualCodegen or policy changes from 462bdd1243dSDimitry Andric // previous iteration. 463fe6060f1SDimitry Andric RVVIntrinsic *PrevDef = Defs.begin()->get(); 464fe6060f1SDimitry Andric for (auto &Def : Defs) { 465fe6060f1SDimitry Andric StringRef CurIRName = Def->getIRName(); 466fe6060f1SDimitry Andric if (CurIRName != PrevDef->getIRName() || 467bdd1243dSDimitry Andric (Def->getManualCodegen() != PrevDef->getManualCodegen()) || 468bdd1243dSDimitry Andric (Def->getPolicyAttrs() != PrevDef->getPolicyAttrs())) { 46981ad6265SDimitry Andric emitCodeGenSwitchBody(PrevDef, OS); 470fe6060f1SDimitry Andric } 471fe6060f1SDimitry Andric PrevDef = Def.get(); 472349cc55cSDimitry Andric 473349cc55cSDimitry Andric auto P = 474349cc55cSDimitry Andric BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); 475349cc55cSDimitry Andric if (P.second) { 476349cc55cSDimitry Andric OS << "case RISCVVector::BI__builtin_rvv_" << Def->getBuiltinName() 477349cc55cSDimitry Andric << ":\n"; 478349cc55cSDimitry Andric continue; 479349cc55cSDimitry Andric } 480349cc55cSDimitry Andric 481349cc55cSDimitry Andric if (P.first->second->getIRName() != Def->getIRName()) 482349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different IRName"); 483349cc55cSDimitry Andric else if (P.first->second->getManualCodegen() != Def->getManualCodegen()) 484349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different ManualCodegen"); 48581ad6265SDimitry Andric else if (P.first->second->isMasked() != Def->isMasked()) 48681ad6265SDimitry Andric PrintFatalError("Builtin with same name has different isMasked"); 487349cc55cSDimitry Andric else if (P.first->second->hasVL() != Def->hasVL()) 48881ad6265SDimitry Andric PrintFatalError("Builtin with same name has different hasVL"); 48981ad6265SDimitry Andric else if (P.first->second->getPolicyScheme() != Def->getPolicyScheme()) 49081ad6265SDimitry Andric PrintFatalError("Builtin with same name has different getPolicyScheme"); 491349cc55cSDimitry Andric else if (P.first->second->getIntrinsicTypes() != Def->getIntrinsicTypes()) 492349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different IntrinsicTypes"); 493fe6060f1SDimitry Andric } 49481ad6265SDimitry Andric emitCodeGenSwitchBody(Defs.back().get(), OS); 495fe6060f1SDimitry Andric OS << "\n"; 496fe6060f1SDimitry Andric } 497fe6060f1SDimitry Andric 498fe6060f1SDimitry Andric void RVVEmitter::createRVVIntrinsics( 499972a253aSDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> &Out, 500972a253aSDimitry Andric std::vector<SemaRecord> *SemaRecords) { 501fe6060f1SDimitry Andric std::vector<Record *> RV = Records.getAllDerivedDefinitions("RVVBuiltin"); 502fe6060f1SDimitry Andric for (auto *R : RV) { 503fe6060f1SDimitry Andric StringRef Name = R->getValueAsString("Name"); 504fe6060f1SDimitry Andric StringRef SuffixProto = R->getValueAsString("Suffix"); 50581ad6265SDimitry Andric StringRef OverloadedName = R->getValueAsString("OverloadedName"); 50681ad6265SDimitry Andric StringRef OverloadedSuffixProto = R->getValueAsString("OverloadedSuffix"); 507fe6060f1SDimitry Andric StringRef Prototypes = R->getValueAsString("Prototype"); 508fe6060f1SDimitry Andric StringRef TypeRange = R->getValueAsString("TypeRange"); 50981ad6265SDimitry Andric bool HasMasked = R->getValueAsBit("HasMasked"); 510fe6060f1SDimitry Andric bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand"); 511fe6060f1SDimitry Andric bool HasVL = R->getValueAsBit("HasVL"); 512972a253aSDimitry Andric Record *MPSRecord = R->getValueAsDef("MaskedPolicyScheme"); 513972a253aSDimitry Andric auto MaskedPolicyScheme = 514972a253aSDimitry Andric static_cast<PolicyScheme>(MPSRecord->getValueAsInt("Value")); 515972a253aSDimitry Andric Record *UMPSRecord = R->getValueAsDef("UnMaskedPolicyScheme"); 516972a253aSDimitry Andric auto UnMaskedPolicyScheme = 517972a253aSDimitry Andric static_cast<PolicyScheme>(UMPSRecord->getValueAsInt("Value")); 518fe6060f1SDimitry Andric std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL"); 519bdd1243dSDimitry Andric bool HasTailPolicy = R->getValueAsBit("HasTailPolicy"); 520bdd1243dSDimitry Andric bool HasMaskPolicy = R->getValueAsBit("HasMaskPolicy"); 521bdd1243dSDimitry Andric bool SupportOverloading = R->getValueAsBit("SupportOverloading"); 52281ad6265SDimitry Andric bool HasBuiltinAlias = R->getValueAsBit("HasBuiltinAlias"); 523fe6060f1SDimitry Andric StringRef ManualCodegen = R->getValueAsString("ManualCodegen"); 524fe6060f1SDimitry Andric std::vector<int64_t> IntrinsicTypes = 525fe6060f1SDimitry Andric R->getValueAsListOfInts("IntrinsicTypes"); 52604eeddc0SDimitry Andric std::vector<StringRef> RequiredFeatures = 52704eeddc0SDimitry Andric R->getValueAsListOfStrings("RequiredFeatures"); 528fe6060f1SDimitry Andric StringRef IRName = R->getValueAsString("IRName"); 52981ad6265SDimitry Andric StringRef MaskedIRName = R->getValueAsString("MaskedIRName"); 530fe6060f1SDimitry Andric unsigned NF = R->getValueAsInt("NF"); 53106c3fb27SDimitry Andric bool IsTuple = R->getValueAsBit("IsTuple"); 53206c3fb27SDimitry Andric bool HasFRMRoundModeOp = R->getValueAsBit("HasFRMRoundModeOp"); 533fe6060f1SDimitry Andric 5341ac55f4cSDimitry Andric const Policy DefaultPolicy; 535bdd1243dSDimitry Andric SmallVector<Policy> SupportedUnMaskedPolicies = 5361ac55f4cSDimitry Andric RVVIntrinsic::getSupportedUnMaskedPolicies(); 537bdd1243dSDimitry Andric SmallVector<Policy> SupportedMaskedPolicies = 538bdd1243dSDimitry Andric RVVIntrinsic::getSupportedMaskedPolicies(HasTailPolicy, HasMaskPolicy); 539bdd1243dSDimitry Andric 540fe6060f1SDimitry Andric // Parse prototype and create a list of primitive type with transformers 54181ad6265SDimitry Andric // (operand) in Prototype. Prototype[0] is output operand. 542972a253aSDimitry Andric SmallVector<PrototypeDescriptor> BasicPrototype = 543972a253aSDimitry Andric parsePrototypes(Prototypes); 54481ad6265SDimitry Andric 54581ad6265SDimitry Andric SmallVector<PrototypeDescriptor> SuffixDesc = parsePrototypes(SuffixProto); 54681ad6265SDimitry Andric SmallVector<PrototypeDescriptor> OverloadedSuffixDesc = 54781ad6265SDimitry Andric parsePrototypes(OverloadedSuffixProto); 548fe6060f1SDimitry Andric 549fe6060f1SDimitry Andric // Compute Builtin types 550972a253aSDimitry Andric auto Prototype = RVVIntrinsic::computeBuiltinTypes( 551bdd1243dSDimitry Andric BasicPrototype, /*IsMasked=*/false, 552bdd1243dSDimitry Andric /*HasMaskedOffOperand=*/false, HasVL, NF, UnMaskedPolicyScheme, 55306c3fb27SDimitry Andric DefaultPolicy, IsTuple); 55406c3fb27SDimitry Andric llvm::SmallVector<PrototypeDescriptor> MaskedPrototype; 55506c3fb27SDimitry Andric if (HasMasked) 55606c3fb27SDimitry Andric MaskedPrototype = RVVIntrinsic::computeBuiltinTypes( 557bdd1243dSDimitry Andric BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, NF, 55806c3fb27SDimitry Andric MaskedPolicyScheme, DefaultPolicy, IsTuple); 559fe6060f1SDimitry Andric 560fe6060f1SDimitry Andric // Create Intrinsics for each type and LMUL. 561fe6060f1SDimitry Andric for (char I : TypeRange) { 562fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULList) { 56381ad6265SDimitry Andric BasicType BT = ParseBasicType(I); 564bdd1243dSDimitry Andric std::optional<RVVTypes> Types = 565bdd1243dSDimitry Andric TypeCache.computeTypes(BT, Log2LMUL, NF, Prototype); 566fe6060f1SDimitry Andric // Ignored to create new intrinsic if there are any illegal types. 56781ad6265SDimitry Andric if (!Types) 568fe6060f1SDimitry Andric continue; 569fe6060f1SDimitry Andric 570bdd1243dSDimitry Andric auto SuffixStr = 571bdd1243dSDimitry Andric RVVIntrinsic::getSuffixStr(TypeCache, BT, Log2LMUL, SuffixDesc); 572bdd1243dSDimitry Andric auto OverloadedSuffixStr = RVVIntrinsic::getSuffixStr( 573bdd1243dSDimitry Andric TypeCache, BT, Log2LMUL, OverloadedSuffixDesc); 57481ad6265SDimitry Andric // Create a unmasked intrinsic 575fe6060f1SDimitry Andric Out.push_back(std::make_unique<RVVIntrinsic>( 57681ad6265SDimitry Andric Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName, 57781ad6265SDimitry Andric /*IsMasked=*/false, /*HasMaskedOffOperand=*/false, HasVL, 578bdd1243dSDimitry Andric UnMaskedPolicyScheme, SupportOverloading, HasBuiltinAlias, 579*0fca6ea1SDimitry Andric ManualCodegen, *Types, IntrinsicTypes, NF, DefaultPolicy, 580*0fca6ea1SDimitry Andric HasFRMRoundModeOp)); 581bdd1243dSDimitry Andric if (UnMaskedPolicyScheme != PolicyScheme::SchemeNone) 582bdd1243dSDimitry Andric for (auto P : SupportedUnMaskedPolicies) { 583bdd1243dSDimitry Andric SmallVector<PrototypeDescriptor> PolicyPrototype = 584bdd1243dSDimitry Andric RVVIntrinsic::computeBuiltinTypes( 585bdd1243dSDimitry Andric BasicPrototype, /*IsMasked=*/false, 586bdd1243dSDimitry Andric /*HasMaskedOffOperand=*/false, HasVL, NF, 58706c3fb27SDimitry Andric UnMaskedPolicyScheme, P, IsTuple); 588bdd1243dSDimitry Andric std::optional<RVVTypes> PolicyTypes = 589bdd1243dSDimitry Andric TypeCache.computeTypes(BT, Log2LMUL, NF, PolicyPrototype); 590bdd1243dSDimitry Andric Out.push_back(std::make_unique<RVVIntrinsic>( 591bdd1243dSDimitry Andric Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName, 592bdd1243dSDimitry Andric /*IsMask=*/false, /*HasMaskedOffOperand=*/false, HasVL, 593bdd1243dSDimitry Andric UnMaskedPolicyScheme, SupportOverloading, HasBuiltinAlias, 594*0fca6ea1SDimitry Andric ManualCodegen, *PolicyTypes, IntrinsicTypes, NF, P, 595*0fca6ea1SDimitry Andric HasFRMRoundModeOp)); 596bdd1243dSDimitry Andric } 597bdd1243dSDimitry Andric if (!HasMasked) 598bdd1243dSDimitry Andric continue; 59981ad6265SDimitry Andric // Create a masked intrinsic 600bdd1243dSDimitry Andric std::optional<RVVTypes> MaskTypes = 601bdd1243dSDimitry Andric TypeCache.computeTypes(BT, Log2LMUL, NF, MaskedPrototype); 602bdd1243dSDimitry Andric Out.push_back(std::make_unique<RVVIntrinsic>( 603bdd1243dSDimitry Andric Name, SuffixStr, OverloadedName, OverloadedSuffixStr, MaskedIRName, 604bdd1243dSDimitry Andric /*IsMasked=*/true, HasMaskedOffOperand, HasVL, MaskedPolicyScheme, 605bdd1243dSDimitry Andric SupportOverloading, HasBuiltinAlias, ManualCodegen, *MaskTypes, 606*0fca6ea1SDimitry Andric IntrinsicTypes, NF, DefaultPolicy, HasFRMRoundModeOp)); 607bdd1243dSDimitry Andric if (MaskedPolicyScheme == PolicyScheme::SchemeNone) 608bdd1243dSDimitry Andric continue; 609bdd1243dSDimitry Andric for (auto P : SupportedMaskedPolicies) { 610bdd1243dSDimitry Andric SmallVector<PrototypeDescriptor> PolicyPrototype = 611bdd1243dSDimitry Andric RVVIntrinsic::computeBuiltinTypes( 612bdd1243dSDimitry Andric BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, 61306c3fb27SDimitry Andric NF, MaskedPolicyScheme, P, IsTuple); 614bdd1243dSDimitry Andric std::optional<RVVTypes> PolicyTypes = 615bdd1243dSDimitry Andric TypeCache.computeTypes(BT, Log2LMUL, NF, PolicyPrototype); 616fe6060f1SDimitry Andric Out.push_back(std::make_unique<RVVIntrinsic>( 61781ad6265SDimitry Andric Name, SuffixStr, OverloadedName, OverloadedSuffixStr, 618bdd1243dSDimitry Andric MaskedIRName, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, 619bdd1243dSDimitry Andric MaskedPolicyScheme, SupportOverloading, HasBuiltinAlias, 620*0fca6ea1SDimitry Andric ManualCodegen, *PolicyTypes, IntrinsicTypes, NF, P, 621*0fca6ea1SDimitry Andric HasFRMRoundModeOp)); 622fe6060f1SDimitry Andric } 623bdd1243dSDimitry Andric } // End for Log2LMULList 624bdd1243dSDimitry Andric } // End for TypeRange 625972a253aSDimitry Andric 626972a253aSDimitry Andric // We don't emit vsetvli and vsetvlimax for SemaRecord. 627972a253aSDimitry Andric // They are written in riscv_vector.td and will emit those marco define in 628972a253aSDimitry Andric // riscv_vector.h 629972a253aSDimitry Andric if (Name == "vsetvli" || Name == "vsetvlimax") 630972a253aSDimitry Andric continue; 631972a253aSDimitry Andric 632972a253aSDimitry Andric if (!SemaRecords) 633972a253aSDimitry Andric continue; 634972a253aSDimitry Andric 635972a253aSDimitry Andric // Create SemaRecord 636972a253aSDimitry Andric SemaRecord SR; 637972a253aSDimitry Andric SR.Name = Name.str(); 638972a253aSDimitry Andric SR.OverloadedName = OverloadedName.str(); 639972a253aSDimitry Andric BasicType TypeRangeMask = BasicType::Unknown; 640972a253aSDimitry Andric for (char I : TypeRange) 641972a253aSDimitry Andric TypeRangeMask |= ParseBasicType(I); 642972a253aSDimitry Andric 643972a253aSDimitry Andric SR.TypeRangeMask = static_cast<unsigned>(TypeRangeMask); 644972a253aSDimitry Andric 645972a253aSDimitry Andric unsigned Log2LMULMask = 0; 646972a253aSDimitry Andric for (int Log2LMUL : Log2LMULList) 647972a253aSDimitry Andric Log2LMULMask |= 1 << (Log2LMUL + 3); 648972a253aSDimitry Andric 649972a253aSDimitry Andric SR.Log2LMULMask = Log2LMULMask; 650972a253aSDimitry Andric 651972a253aSDimitry Andric SR.RequiredExtensions = 0; 652972a253aSDimitry Andric for (auto RequiredFeature : RequiredFeatures) { 653cb14a3feSDimitry Andric RVVRequire RequireExt = 654cb14a3feSDimitry Andric StringSwitch<RVVRequire>(RequiredFeature) 655972a253aSDimitry Andric .Case("RV64", RVV_REQ_RV64) 6567a6dacacSDimitry Andric .Case("Zvfhmin", RVV_REQ_Zvfhmin) 65706c3fb27SDimitry Andric .Case("Xsfvcp", RVV_REQ_Xsfvcp) 6585f757f3fSDimitry Andric .Case("Xsfvfnrclipxfqf", RVV_REQ_Xsfvfnrclipxfqf) 6595f757f3fSDimitry Andric .Case("Xsfvfwmaccqqq", RVV_REQ_Xsfvfwmaccqqq) 6605f757f3fSDimitry Andric .Case("Xsfvqmaccdod", RVV_REQ_Xsfvqmaccdod) 6615f757f3fSDimitry Andric .Case("Xsfvqmaccqoq", RVV_REQ_Xsfvqmaccqoq) 6625f757f3fSDimitry Andric .Case("Zvbb", RVV_REQ_Zvbb) 6635f757f3fSDimitry Andric .Case("Zvbc", RVV_REQ_Zvbc) 6645f757f3fSDimitry Andric .Case("Zvkb", RVV_REQ_Zvkb) 6655f757f3fSDimitry Andric .Case("Zvkg", RVV_REQ_Zvkg) 6665f757f3fSDimitry Andric .Case("Zvkned", RVV_REQ_Zvkned) 6675f757f3fSDimitry Andric .Case("Zvknha", RVV_REQ_Zvknha) 6685f757f3fSDimitry Andric .Case("Zvknhb", RVV_REQ_Zvknhb) 6695f757f3fSDimitry Andric .Case("Zvksed", RVV_REQ_Zvksed) 6705f757f3fSDimitry Andric .Case("Zvksh", RVV_REQ_Zvksh) 671*0fca6ea1SDimitry Andric .Case("Zvfbfwma", RVV_REQ_Zvfbfwma) 672*0fca6ea1SDimitry Andric .Case("Zvfbfmin", RVV_REQ_Zvfbfmin) 673cb14a3feSDimitry Andric .Case("Experimental", RVV_REQ_Experimental) 674972a253aSDimitry Andric .Default(RVV_REQ_None); 675972a253aSDimitry Andric assert(RequireExt != RVV_REQ_None && "Unrecognized required feature?"); 676972a253aSDimitry Andric SR.RequiredExtensions |= RequireExt; 677972a253aSDimitry Andric } 678972a253aSDimitry Andric 679972a253aSDimitry Andric SR.NF = NF; 680972a253aSDimitry Andric SR.HasMasked = HasMasked; 681972a253aSDimitry Andric SR.HasVL = HasVL; 682972a253aSDimitry Andric SR.HasMaskedOffOperand = HasMaskedOffOperand; 683bdd1243dSDimitry Andric SR.HasTailPolicy = HasTailPolicy; 684bdd1243dSDimitry Andric SR.HasMaskPolicy = HasMaskPolicy; 685bdd1243dSDimitry Andric SR.UnMaskedPolicyScheme = static_cast<uint8_t>(UnMaskedPolicyScheme); 686bdd1243dSDimitry Andric SR.MaskedPolicyScheme = static_cast<uint8_t>(MaskedPolicyScheme); 687972a253aSDimitry Andric SR.Prototype = std::move(BasicPrototype); 688972a253aSDimitry Andric SR.Suffix = parsePrototypes(SuffixProto); 689972a253aSDimitry Andric SR.OverloadedSuffix = parsePrototypes(OverloadedSuffixProto); 69006c3fb27SDimitry Andric SR.IsTuple = IsTuple; 69106c3fb27SDimitry Andric SR.HasFRMRoundModeOp = HasFRMRoundModeOp; 692972a253aSDimitry Andric 693972a253aSDimitry Andric SemaRecords->push_back(SR); 694fe6060f1SDimitry Andric } 695fe6060f1SDimitry Andric } 696fe6060f1SDimitry Andric 69781ad6265SDimitry Andric void RVVEmitter::printHeaderCode(raw_ostream &OS) { 698349cc55cSDimitry Andric std::vector<Record *> RVVHeaders = 699349cc55cSDimitry Andric Records.getAllDerivedDefinitions("RVVHeader"); 700349cc55cSDimitry Andric for (auto *R : RVVHeaders) { 701349cc55cSDimitry Andric StringRef HeaderCodeStr = R->getValueAsString("HeaderCode"); 702349cc55cSDimitry Andric OS << HeaderCodeStr.str(); 703349cc55cSDimitry Andric } 704349cc55cSDimitry Andric } 705349cc55cSDimitry Andric 706972a253aSDimitry Andric void RVVEmitter::createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out, 707972a253aSDimitry Andric SemaSignatureTable &SST, 708972a253aSDimitry Andric ArrayRef<SemaRecord> SemaRecords) { 709972a253aSDimitry Andric SST.init(SemaRecords); 710972a253aSDimitry Andric 711972a253aSDimitry Andric for (const auto &SR : SemaRecords) { 712972a253aSDimitry Andric Out.emplace_back(RVVIntrinsicRecord()); 713972a253aSDimitry Andric RVVIntrinsicRecord &R = Out.back(); 714972a253aSDimitry Andric R.Name = SR.Name.c_str(); 715972a253aSDimitry Andric R.OverloadedName = SR.OverloadedName.c_str(); 716972a253aSDimitry Andric R.PrototypeIndex = SST.getIndex(SR.Prototype); 717972a253aSDimitry Andric R.SuffixIndex = SST.getIndex(SR.Suffix); 718972a253aSDimitry Andric R.OverloadedSuffixIndex = SST.getIndex(SR.OverloadedSuffix); 719972a253aSDimitry Andric R.PrototypeLength = SR.Prototype.size(); 720972a253aSDimitry Andric R.SuffixLength = SR.Suffix.size(); 721972a253aSDimitry Andric R.OverloadedSuffixSize = SR.OverloadedSuffix.size(); 722972a253aSDimitry Andric R.RequiredExtensions = SR.RequiredExtensions; 723972a253aSDimitry Andric R.TypeRangeMask = SR.TypeRangeMask; 724972a253aSDimitry Andric R.Log2LMULMask = SR.Log2LMULMask; 725972a253aSDimitry Andric R.NF = SR.NF; 726972a253aSDimitry Andric R.HasMasked = SR.HasMasked; 727972a253aSDimitry Andric R.HasVL = SR.HasVL; 728972a253aSDimitry Andric R.HasMaskedOffOperand = SR.HasMaskedOffOperand; 729bdd1243dSDimitry Andric R.HasTailPolicy = SR.HasTailPolicy; 730bdd1243dSDimitry Andric R.HasMaskPolicy = SR.HasMaskPolicy; 731bdd1243dSDimitry Andric R.UnMaskedPolicyScheme = SR.UnMaskedPolicyScheme; 732bdd1243dSDimitry Andric R.MaskedPolicyScheme = SR.MaskedPolicyScheme; 73306c3fb27SDimitry Andric R.IsTuple = SR.IsTuple; 73406c3fb27SDimitry Andric R.HasFRMRoundModeOp = SR.HasFRMRoundModeOp; 735972a253aSDimitry Andric 736972a253aSDimitry Andric assert(R.PrototypeIndex != 737972a253aSDimitry Andric static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 738972a253aSDimitry Andric assert(R.SuffixIndex != 739972a253aSDimitry Andric static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 740972a253aSDimitry Andric assert(R.OverloadedSuffixIndex != 741972a253aSDimitry Andric static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 742fe6060f1SDimitry Andric } 743fe6060f1SDimitry Andric } 744fe6060f1SDimitry Andric 745972a253aSDimitry Andric void RVVEmitter::createSema(raw_ostream &OS) { 746972a253aSDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 747972a253aSDimitry Andric std::vector<RVVIntrinsicRecord> RVVIntrinsicRecords; 748972a253aSDimitry Andric SemaSignatureTable SST; 749972a253aSDimitry Andric std::vector<SemaRecord> SemaRecords; 750972a253aSDimitry Andric 751972a253aSDimitry Andric createRVVIntrinsics(Defs, &SemaRecords); 752972a253aSDimitry Andric 753972a253aSDimitry Andric createRVVIntrinsicRecords(RVVIntrinsicRecords, SST, SemaRecords); 754972a253aSDimitry Andric 755972a253aSDimitry Andric // Emit signature table for SemaRISCVVectorLookup.cpp. 756972a253aSDimitry Andric OS << "#ifdef DECL_SIGNATURE_TABLE\n"; 757972a253aSDimitry Andric SST.print(OS); 758972a253aSDimitry Andric OS << "#endif\n"; 759972a253aSDimitry Andric 760972a253aSDimitry Andric // Emit RVVIntrinsicRecords for SemaRISCVVectorLookup.cpp. 761972a253aSDimitry Andric OS << "#ifdef DECL_INTRINSIC_RECORDS\n"; 762972a253aSDimitry Andric for (const RVVIntrinsicRecord &Record : RVVIntrinsicRecords) 763972a253aSDimitry Andric OS << Record; 764972a253aSDimitry Andric OS << "#endif\n"; 765fe6060f1SDimitry Andric } 766fe6060f1SDimitry Andric 767fe6060f1SDimitry Andric namespace clang { 768fe6060f1SDimitry Andric void EmitRVVHeader(RecordKeeper &Records, raw_ostream &OS) { 769fe6060f1SDimitry Andric RVVEmitter(Records).createHeader(OS); 770fe6060f1SDimitry Andric } 771fe6060f1SDimitry Andric 772fe6060f1SDimitry Andric void EmitRVVBuiltins(RecordKeeper &Records, raw_ostream &OS) { 773fe6060f1SDimitry Andric RVVEmitter(Records).createBuiltins(OS); 774fe6060f1SDimitry Andric } 775fe6060f1SDimitry Andric 776fe6060f1SDimitry Andric void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 777fe6060f1SDimitry Andric RVVEmitter(Records).createCodeGen(OS); 778fe6060f1SDimitry Andric } 779fe6060f1SDimitry Andric 780972a253aSDimitry Andric void EmitRVVBuiltinSema(RecordKeeper &Records, raw_ostream &OS) { 781972a253aSDimitry Andric RVVEmitter(Records).createSema(OS); 782972a253aSDimitry Andric } 783972a253aSDimitry Andric 784fe6060f1SDimitry Andric } // End namespace clang 785