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. 49*cb14a3feSDimitry 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; 70bdd1243dSDimitry Andric uint8_t UnMaskedPolicyScheme : 2; 71bdd1243dSDimitry Andric uint8_t MaskedPolicyScheme : 2; 72972a253aSDimitry Andric }; 73972a253aSDimitry Andric 74972a253aSDimitry Andric // Compressed function signature table. 75972a253aSDimitry Andric class SemaSignatureTable { 76972a253aSDimitry Andric private: 77972a253aSDimitry Andric std::vector<PrototypeDescriptor> SignatureTable; 78972a253aSDimitry Andric 79972a253aSDimitry Andric void insert(ArrayRef<PrototypeDescriptor> Signature); 80972a253aSDimitry Andric 81972a253aSDimitry Andric public: 82972a253aSDimitry Andric static constexpr unsigned INVALID_INDEX = ~0U; 83972a253aSDimitry Andric 84972a253aSDimitry Andric // Create compressed signature table from SemaRecords. 85972a253aSDimitry Andric void init(ArrayRef<SemaRecord> SemaRecords); 86972a253aSDimitry Andric 87972a253aSDimitry Andric // Query the Signature, return INVALID_INDEX if not found. 88972a253aSDimitry Andric unsigned getIndex(ArrayRef<PrototypeDescriptor> Signature); 89972a253aSDimitry Andric 90972a253aSDimitry Andric /// Print signature table in RVVHeader Record to \p OS 91972a253aSDimitry Andric void print(raw_ostream &OS); 92972a253aSDimitry Andric }; 93972a253aSDimitry Andric 94fe6060f1SDimitry Andric class RVVEmitter { 95fe6060f1SDimitry Andric private: 96fe6060f1SDimitry Andric RecordKeeper &Records; 97bdd1243dSDimitry Andric RVVTypeCache TypeCache; 98fe6060f1SDimitry Andric 99fe6060f1SDimitry Andric public: 100fe6060f1SDimitry Andric RVVEmitter(RecordKeeper &R) : Records(R) {} 101fe6060f1SDimitry Andric 102fe6060f1SDimitry Andric /// Emit riscv_vector.h 103fe6060f1SDimitry Andric void createHeader(raw_ostream &o); 104fe6060f1SDimitry Andric 105fe6060f1SDimitry Andric /// Emit all the __builtin prototypes and code needed by Sema. 106fe6060f1SDimitry Andric void createBuiltins(raw_ostream &o); 107fe6060f1SDimitry Andric 108fe6060f1SDimitry Andric /// Emit all the information needed to map builtin -> LLVM IR intrinsic. 109fe6060f1SDimitry Andric void createCodeGen(raw_ostream &o); 110fe6060f1SDimitry Andric 111972a253aSDimitry Andric /// Emit all the information needed by SemaRISCVVectorLookup.cpp. 112972a253aSDimitry Andric /// We've large number of intrinsic function for RVV, creating a customized 113972a253aSDimitry Andric /// could speed up the compilation time. 114972a253aSDimitry Andric void createSema(raw_ostream &o); 115972a253aSDimitry Andric 116fe6060f1SDimitry Andric private: 117972a253aSDimitry Andric /// Create all intrinsics and add them to \p Out and SemaRecords. 118972a253aSDimitry Andric void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out, 119972a253aSDimitry Andric std::vector<SemaRecord> *SemaRecords = nullptr); 120972a253aSDimitry Andric /// Create all intrinsic records and SemaSignatureTable from SemaRecords. 121972a253aSDimitry Andric void createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out, 122972a253aSDimitry Andric SemaSignatureTable &SST, 123972a253aSDimitry Andric ArrayRef<SemaRecord> SemaRecords); 124972a253aSDimitry Andric 12581ad6265SDimitry Andric /// Print HeaderCode in RVVHeader Record to \p Out 12681ad6265SDimitry Andric void printHeaderCode(raw_ostream &OS); 127fe6060f1SDimitry Andric }; 128fe6060f1SDimitry Andric 129fe6060f1SDimitry Andric } // namespace 130fe6060f1SDimitry Andric 13181ad6265SDimitry Andric static BasicType ParseBasicType(char c) { 13281ad6265SDimitry Andric switch (c) { 133fe6060f1SDimitry Andric case 'c': 13481ad6265SDimitry Andric return BasicType::Int8; 135fe6060f1SDimitry Andric break; 136fe6060f1SDimitry Andric case 's': 13781ad6265SDimitry Andric return BasicType::Int16; 138fe6060f1SDimitry Andric break; 139fe6060f1SDimitry Andric case 'i': 14081ad6265SDimitry Andric return BasicType::Int32; 141fe6060f1SDimitry Andric break; 142fe6060f1SDimitry Andric case 'l': 14381ad6265SDimitry Andric return BasicType::Int64; 144fe6060f1SDimitry Andric break; 145fe6060f1SDimitry Andric case 'x': 14681ad6265SDimitry Andric return BasicType::Float16; 147fe6060f1SDimitry Andric break; 148fe6060f1SDimitry Andric case 'f': 14981ad6265SDimitry Andric return BasicType::Float32; 150fe6060f1SDimitry Andric break; 151fe6060f1SDimitry Andric case 'd': 15281ad6265SDimitry Andric return BasicType::Float64; 153fe6060f1SDimitry Andric break; 1545f757f3fSDimitry Andric case 'b': 1555f757f3fSDimitry Andric return BasicType::BFloat16; 1565f757f3fSDimitry Andric break; 157fe6060f1SDimitry Andric default: 15881ad6265SDimitry Andric return BasicType::Unknown; 159fe6060f1SDimitry Andric } 160fe6060f1SDimitry Andric } 161fe6060f1SDimitry Andric 16206c3fb27SDimitry Andric static VectorTypeModifier getTupleVTM(unsigned NF) { 16306c3fb27SDimitry Andric assert(2 <= NF && NF <= 8 && "2 <= NF <= 8"); 16406c3fb27SDimitry Andric return static_cast<VectorTypeModifier>( 16506c3fb27SDimitry Andric static_cast<uint8_t>(VectorTypeModifier::Tuple2) + (NF - 2)); 16606c3fb27SDimitry Andric } 16706c3fb27SDimitry Andric 16881ad6265SDimitry Andric void emitCodeGenSwitchBody(const RVVIntrinsic *RVVI, raw_ostream &OS) { 16981ad6265SDimitry Andric if (!RVVI->getIRName().empty()) 17081ad6265SDimitry Andric OS << " ID = Intrinsic::riscv_" + RVVI->getIRName() + ";\n"; 17181ad6265SDimitry Andric if (RVVI->getNF() >= 2) 17281ad6265SDimitry Andric OS << " NF = " + utostr(RVVI->getNF()) + ";\n"; 173bdd1243dSDimitry Andric 174bdd1243dSDimitry Andric OS << " PolicyAttrs = " << RVVI->getPolicyAttrsBits() << ";\n"; 175bdd1243dSDimitry Andric 17681ad6265SDimitry Andric if (RVVI->hasManualCodegen()) { 177bdd1243dSDimitry Andric OS << "IsMasked = " << (RVVI->isMasked() ? "true" : "false") << ";\n"; 17881ad6265SDimitry Andric OS << RVVI->getManualCodegen(); 179fe6060f1SDimitry Andric OS << "break;\n"; 180fe6060f1SDimitry Andric return; 181fe6060f1SDimitry Andric } 182fe6060f1SDimitry Andric 183753f127fSDimitry Andric for (const auto &I : enumerate(RVVI->getInputTypes())) { 184753f127fSDimitry Andric if (I.value()->isPointer()) { 185753f127fSDimitry Andric assert(RVVI->getIntrinsicTypes().front() == -1 && 186753f127fSDimitry Andric "RVVI should be vector load intrinsic."); 187753f127fSDimitry Andric } 188753f127fSDimitry Andric } 189753f127fSDimitry Andric 19081ad6265SDimitry Andric if (RVVI->isMasked()) { 19181ad6265SDimitry Andric if (RVVI->hasVL()) { 192fe6060f1SDimitry Andric OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n"; 19381ad6265SDimitry Andric if (RVVI->hasPolicyOperand()) 194349cc55cSDimitry Andric OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType()," 195bdd1243dSDimitry Andric " PolicyAttrs));\n"; 196bdd1243dSDimitry Andric if (RVVI->hasMaskedOffOperand() && RVVI->getPolicyAttrs().isTAMAPolicy()) 197bdd1243dSDimitry Andric OS << " Ops.insert(Ops.begin(), " 198bdd1243dSDimitry Andric "llvm::PoisonValue::get(ResultType));\n"; 199bdd1243dSDimitry Andric // Masked reduction cases. 200bdd1243dSDimitry Andric if (!RVVI->hasMaskedOffOperand() && RVVI->hasPassthruOperand() && 201bdd1243dSDimitry Andric RVVI->getPolicyAttrs().isTAMAPolicy()) 202bdd1243dSDimitry Andric OS << " Ops.insert(Ops.begin(), " 203bdd1243dSDimitry Andric "llvm::PoisonValue::get(ResultType));\n"; 204fe6060f1SDimitry Andric } else { 205fe6060f1SDimitry Andric OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n"; 206fe6060f1SDimitry Andric } 20781ad6265SDimitry Andric } else { 20881ad6265SDimitry Andric if (RVVI->hasPolicyOperand()) 20981ad6265SDimitry Andric OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(), " 210bdd1243dSDimitry Andric "PolicyAttrs));\n"; 211bdd1243dSDimitry Andric else if (RVVI->hasPassthruOperand() && RVVI->getPolicyAttrs().isTAPolicy()) 212bdd1243dSDimitry Andric OS << " Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));\n"; 213fe6060f1SDimitry Andric } 214fe6060f1SDimitry Andric 215fe6060f1SDimitry Andric OS << " IntrinsicTypes = {"; 216fe6060f1SDimitry Andric ListSeparator LS; 21781ad6265SDimitry Andric for (const auto &Idx : RVVI->getIntrinsicTypes()) { 218fe6060f1SDimitry Andric if (Idx == -1) 219fe6060f1SDimitry Andric OS << LS << "ResultType"; 220fe6060f1SDimitry Andric else 221fe6060f1SDimitry Andric OS << LS << "Ops[" << Idx << "]->getType()"; 222fe6060f1SDimitry Andric } 223fe6060f1SDimitry Andric 224fe6060f1SDimitry Andric // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is 225fe6060f1SDimitry Andric // always last operand. 22681ad6265SDimitry Andric if (RVVI->hasVL()) 227fe6060f1SDimitry Andric OS << ", Ops.back()->getType()"; 228fe6060f1SDimitry Andric OS << "};\n"; 229fe6060f1SDimitry Andric OS << " break;\n"; 230fe6060f1SDimitry Andric } 231fe6060f1SDimitry Andric 232972a253aSDimitry Andric //===----------------------------------------------------------------------===// 233972a253aSDimitry Andric // SemaSignatureTable implementation 234972a253aSDimitry Andric //===----------------------------------------------------------------------===// 235972a253aSDimitry Andric void SemaSignatureTable::init(ArrayRef<SemaRecord> SemaRecords) { 236972a253aSDimitry Andric // Sort signature entries by length, let longer signature insert first, to 237972a253aSDimitry Andric // make it more possible to reuse table entries, that can reduce ~10% table 238972a253aSDimitry Andric // size. 239972a253aSDimitry Andric struct Compare { 240972a253aSDimitry Andric bool operator()(const SmallVector<PrototypeDescriptor> &A, 241972a253aSDimitry Andric const SmallVector<PrototypeDescriptor> &B) const { 242972a253aSDimitry Andric if (A.size() != B.size()) 243972a253aSDimitry Andric return A.size() > B.size(); 244972a253aSDimitry Andric 245972a253aSDimitry Andric size_t Len = A.size(); 246972a253aSDimitry Andric for (size_t i = 0; i < Len; ++i) { 247972a253aSDimitry Andric if (A[i] != B[i]) 248972a253aSDimitry Andric return A[i] < B[i]; 249fe6060f1SDimitry Andric } 250fe6060f1SDimitry Andric 251972a253aSDimitry Andric return false; 252fe6060f1SDimitry Andric } 253972a253aSDimitry Andric }; 254972a253aSDimitry Andric 255972a253aSDimitry Andric std::set<SmallVector<PrototypeDescriptor>, Compare> Signatures; 256972a253aSDimitry Andric auto InsertToSignatureSet = 257972a253aSDimitry Andric [&](const SmallVector<PrototypeDescriptor> &Signature) { 258972a253aSDimitry Andric if (Signature.empty()) 259972a253aSDimitry Andric return; 260972a253aSDimitry Andric 261972a253aSDimitry Andric Signatures.insert(Signature); 262972a253aSDimitry Andric }; 263972a253aSDimitry Andric 264972a253aSDimitry Andric assert(!SemaRecords.empty()); 265972a253aSDimitry Andric 2665f757f3fSDimitry Andric for (const SemaRecord &SR : SemaRecords) { 267972a253aSDimitry Andric InsertToSignatureSet(SR.Prototype); 268972a253aSDimitry Andric InsertToSignatureSet(SR.Suffix); 269972a253aSDimitry Andric InsertToSignatureSet(SR.OverloadedSuffix); 2705f757f3fSDimitry Andric } 271972a253aSDimitry Andric 2725f757f3fSDimitry Andric for (auto &Sig : Signatures) 2735f757f3fSDimitry Andric insert(Sig); 274972a253aSDimitry Andric } 275972a253aSDimitry Andric 276972a253aSDimitry Andric void SemaSignatureTable::insert(ArrayRef<PrototypeDescriptor> Signature) { 277972a253aSDimitry Andric if (getIndex(Signature) != INVALID_INDEX) 278972a253aSDimitry Andric return; 279972a253aSDimitry Andric 280972a253aSDimitry Andric // Insert Signature into SignatureTable if not found in the table. 281972a253aSDimitry Andric SignatureTable.insert(SignatureTable.begin(), Signature.begin(), 282972a253aSDimitry Andric Signature.end()); 283972a253aSDimitry Andric } 284972a253aSDimitry Andric 285972a253aSDimitry Andric unsigned SemaSignatureTable::getIndex(ArrayRef<PrototypeDescriptor> Signature) { 286972a253aSDimitry Andric // Empty signature could be point into any index since there is length 287972a253aSDimitry Andric // field when we use, so just always point it to 0. 288972a253aSDimitry Andric if (Signature.empty()) 289972a253aSDimitry Andric return 0; 290972a253aSDimitry Andric 291972a253aSDimitry Andric // Checking Signature already in table or not. 2925f757f3fSDimitry Andric if (Signature.size() <= SignatureTable.size()) { 293972a253aSDimitry Andric size_t Bound = SignatureTable.size() - Signature.size() + 1; 294972a253aSDimitry Andric for (size_t Index = 0; Index < Bound; ++Index) { 295972a253aSDimitry Andric if (equal(Signature.begin(), Signature.end(), 296972a253aSDimitry Andric SignatureTable.begin() + Index)) 297972a253aSDimitry Andric return Index; 298972a253aSDimitry Andric } 299972a253aSDimitry Andric } 300972a253aSDimitry Andric 301972a253aSDimitry Andric return INVALID_INDEX; 302972a253aSDimitry Andric } 303972a253aSDimitry Andric 304972a253aSDimitry Andric void SemaSignatureTable::print(raw_ostream &OS) { 305972a253aSDimitry Andric for (const auto &Sig : SignatureTable) 306972a253aSDimitry Andric OS << "PrototypeDescriptor(" << static_cast<int>(Sig.PT) << ", " 307972a253aSDimitry Andric << static_cast<int>(Sig.VTM) << ", " << static_cast<int>(Sig.TM) 308972a253aSDimitry Andric << "),\n"; 309fe6060f1SDimitry Andric } 310fe6060f1SDimitry Andric 311fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 312fe6060f1SDimitry Andric // RVVEmitter implementation 313fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 314fe6060f1SDimitry Andric void RVVEmitter::createHeader(raw_ostream &OS) { 315fe6060f1SDimitry Andric 316fe6060f1SDimitry Andric OS << "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics " 317fe6060f1SDimitry Andric "-------------------===\n" 318fe6060f1SDimitry Andric " *\n" 319fe6060f1SDimitry Andric " *\n" 320fe6060f1SDimitry Andric " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " 321fe6060f1SDimitry Andric "Exceptions.\n" 322fe6060f1SDimitry Andric " * See https://llvm.org/LICENSE.txt for license information.\n" 323fe6060f1SDimitry Andric " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 324fe6060f1SDimitry Andric " *\n" 325fe6060f1SDimitry Andric " *===-----------------------------------------------------------------" 326fe6060f1SDimitry Andric "------===\n" 327fe6060f1SDimitry Andric " */\n\n"; 328fe6060f1SDimitry Andric 329fe6060f1SDimitry Andric OS << "#ifndef __RISCV_VECTOR_H\n"; 330fe6060f1SDimitry Andric OS << "#define __RISCV_VECTOR_H\n\n"; 331fe6060f1SDimitry Andric 332fe6060f1SDimitry Andric OS << "#include <stdint.h>\n"; 333fe6060f1SDimitry Andric OS << "#include <stddef.h>\n\n"; 334fe6060f1SDimitry Andric 335fe6060f1SDimitry Andric OS << "#ifndef __riscv_vector\n"; 336fe6060f1SDimitry Andric OS << "#error \"Vector intrinsics require the vector extension.\"\n"; 337fe6060f1SDimitry Andric OS << "#endif\n\n"; 338fe6060f1SDimitry Andric 339fe6060f1SDimitry Andric OS << "#ifdef __cplusplus\n"; 340fe6060f1SDimitry Andric OS << "extern \"C\" {\n"; 341fe6060f1SDimitry Andric OS << "#endif\n\n"; 342fe6060f1SDimitry Andric 343972a253aSDimitry Andric OS << "#pragma clang riscv intrinsic vector\n\n"; 344349cc55cSDimitry Andric 345972a253aSDimitry Andric printHeaderCode(OS); 346fe6060f1SDimitry Andric 347fe6060f1SDimitry Andric auto printType = [&](auto T) { 348fe6060f1SDimitry Andric OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr() 349fe6060f1SDimitry Andric << ";\n"; 350fe6060f1SDimitry Andric }; 351fe6060f1SDimitry Andric 352fe6060f1SDimitry Andric constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3}; 353fe6060f1SDimitry Andric // Print RVV boolean types. 354fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 355bdd1243dSDimitry Andric auto T = TypeCache.computeType(BasicType::Int8, Log2LMUL, 35681ad6265SDimitry Andric PrototypeDescriptor::Mask); 35781ad6265SDimitry Andric if (T) 358bdd1243dSDimitry Andric printType(*T); 359fe6060f1SDimitry Andric } 360fe6060f1SDimitry Andric // Print RVV int/float types. 361fe6060f1SDimitry Andric for (char I : StringRef("csil")) { 36281ad6265SDimitry Andric BasicType BT = ParseBasicType(I); 363fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 364bdd1243dSDimitry Andric auto T = TypeCache.computeType(BT, Log2LMUL, PrototypeDescriptor::Vector); 36581ad6265SDimitry Andric if (T) { 366bdd1243dSDimitry Andric printType(*T); 367bdd1243dSDimitry Andric auto UT = TypeCache.computeType( 36881ad6265SDimitry Andric BT, Log2LMUL, 36981ad6265SDimitry Andric PrototypeDescriptor(BaseTypeModifier::Vector, 37081ad6265SDimitry Andric VectorTypeModifier::NoModifier, 37181ad6265SDimitry Andric TypeModifier::UnsignedInteger)); 372bdd1243dSDimitry Andric printType(*UT); 373fe6060f1SDimitry Andric } 37406c3fb27SDimitry Andric for (int NF = 2; NF <= 8; ++NF) { 37506c3fb27SDimitry Andric auto TupleT = TypeCache.computeType( 37606c3fb27SDimitry Andric BT, Log2LMUL, 37706c3fb27SDimitry Andric PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF), 37806c3fb27SDimitry Andric TypeModifier::SignedInteger)); 37906c3fb27SDimitry Andric auto TupleUT = TypeCache.computeType( 38006c3fb27SDimitry Andric BT, Log2LMUL, 38106c3fb27SDimitry Andric PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF), 38206c3fb27SDimitry Andric TypeModifier::UnsignedInteger)); 38306c3fb27SDimitry Andric if (TupleT) 38406c3fb27SDimitry Andric printType(*TupleT); 38506c3fb27SDimitry Andric if (TupleUT) 38606c3fb27SDimitry Andric printType(*TupleUT); 387fe6060f1SDimitry Andric } 388fe6060f1SDimitry Andric } 389fe6060f1SDimitry Andric } 390fe6060f1SDimitry Andric 3915f757f3fSDimitry Andric for (BasicType BT : {BasicType::Float16, BasicType::Float32, 3925f757f3fSDimitry Andric BasicType::Float64, BasicType::BFloat16}) { 393fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 39406c3fb27SDimitry Andric auto T = TypeCache.computeType(BT, Log2LMUL, PrototypeDescriptor::Vector); 39581ad6265SDimitry Andric if (T) 396bdd1243dSDimitry Andric printType(*T); 39706c3fb27SDimitry Andric for (int NF = 2; NF <= 8; ++NF) { 39806c3fb27SDimitry Andric auto TupleT = TypeCache.computeType( 39906c3fb27SDimitry Andric BT, Log2LMUL, 40006c3fb27SDimitry Andric PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF), 4015f757f3fSDimitry Andric (BT == BasicType::BFloat16 4025f757f3fSDimitry Andric ? TypeModifier::BFloat 4035f757f3fSDimitry Andric : TypeModifier::Float))); 40406c3fb27SDimitry Andric if (TupleT) 40506c3fb27SDimitry Andric printType(*TupleT); 406fe6060f1SDimitry Andric } 407fe6060f1SDimitry Andric } 40806c3fb27SDimitry Andric } 409fe6060f1SDimitry Andric 410fe6060f1SDimitry Andric OS << "#define __riscv_v_intrinsic_overloading 1\n"; 411fe6060f1SDimitry Andric 412fe6060f1SDimitry Andric OS << "\n#ifdef __cplusplus\n"; 413fe6060f1SDimitry Andric OS << "}\n"; 414349cc55cSDimitry Andric OS << "#endif // __cplusplus\n"; 415fe6060f1SDimitry Andric OS << "#endif // __RISCV_VECTOR_H\n"; 416fe6060f1SDimitry Andric } 417fe6060f1SDimitry Andric 418fe6060f1SDimitry Andric void RVVEmitter::createBuiltins(raw_ostream &OS) { 419fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 420fe6060f1SDimitry Andric createRVVIntrinsics(Defs); 421fe6060f1SDimitry Andric 422349cc55cSDimitry Andric // Map to keep track of which builtin names have already been emitted. 423349cc55cSDimitry Andric StringMap<RVVIntrinsic *> BuiltinMap; 424349cc55cSDimitry Andric 425fe6060f1SDimitry Andric OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n"; 426fe6060f1SDimitry Andric OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, " 42781ad6265SDimitry Andric "ATTRS, \"zve32x\")\n"; 428fe6060f1SDimitry Andric OS << "#endif\n"; 429fe6060f1SDimitry Andric for (auto &Def : Defs) { 430349cc55cSDimitry Andric auto P = 431349cc55cSDimitry Andric BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); 432349cc55cSDimitry Andric if (!P.second) { 43381ad6265SDimitry Andric // Verf that this would have produced the same builtin definition. 43481ad6265SDimitry Andric if (P.first->second->hasBuiltinAlias() != Def->hasBuiltinAlias()) 435349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different hasAutoDef"); 43681ad6265SDimitry Andric else if (!Def->hasBuiltinAlias() && 43781ad6265SDimitry Andric P.first->second->getBuiltinTypeStr() != Def->getBuiltinTypeStr()) 438349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different type string"); 439349cc55cSDimitry Andric continue; 440349cc55cSDimitry Andric } 441349cc55cSDimitry Andric OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getBuiltinName() << ",\""; 44281ad6265SDimitry Andric if (!Def->hasBuiltinAlias()) 443349cc55cSDimitry Andric OS << Def->getBuiltinTypeStr(); 444349cc55cSDimitry Andric OS << "\", \"n\")\n"; 445fe6060f1SDimitry Andric } 446fe6060f1SDimitry Andric OS << "#undef RISCVV_BUILTIN\n"; 447fe6060f1SDimitry Andric } 448fe6060f1SDimitry Andric 449fe6060f1SDimitry Andric void RVVEmitter::createCodeGen(raw_ostream &OS) { 450fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 451fe6060f1SDimitry Andric createRVVIntrinsics(Defs); 452fe6060f1SDimitry Andric // IR name could be empty, use the stable sort preserves the relative order. 453349cc55cSDimitry Andric llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A, 454fe6060f1SDimitry Andric const std::unique_ptr<RVVIntrinsic> &B) { 455bdd1243dSDimitry Andric if (A->getIRName() == B->getIRName()) 456bdd1243dSDimitry Andric return (A->getPolicyAttrs() < B->getPolicyAttrs()); 457bdd1243dSDimitry Andric return (A->getIRName() < B->getIRName()); 458fe6060f1SDimitry Andric }); 459349cc55cSDimitry Andric 460349cc55cSDimitry Andric // Map to keep track of which builtin names have already been emitted. 461349cc55cSDimitry Andric StringMap<RVVIntrinsic *> BuiltinMap; 462349cc55cSDimitry Andric 463bdd1243dSDimitry Andric // Print switch body when the ir name, ManualCodegen or policy changes from 464bdd1243dSDimitry Andric // previous iteration. 465fe6060f1SDimitry Andric RVVIntrinsic *PrevDef = Defs.begin()->get(); 466fe6060f1SDimitry Andric for (auto &Def : Defs) { 467fe6060f1SDimitry Andric StringRef CurIRName = Def->getIRName(); 468fe6060f1SDimitry Andric if (CurIRName != PrevDef->getIRName() || 469bdd1243dSDimitry Andric (Def->getManualCodegen() != PrevDef->getManualCodegen()) || 470bdd1243dSDimitry Andric (Def->getPolicyAttrs() != PrevDef->getPolicyAttrs())) { 47181ad6265SDimitry Andric emitCodeGenSwitchBody(PrevDef, OS); 472fe6060f1SDimitry Andric } 473fe6060f1SDimitry Andric PrevDef = Def.get(); 474349cc55cSDimitry Andric 475349cc55cSDimitry Andric auto P = 476349cc55cSDimitry Andric BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); 477349cc55cSDimitry Andric if (P.second) { 478349cc55cSDimitry Andric OS << "case RISCVVector::BI__builtin_rvv_" << Def->getBuiltinName() 479349cc55cSDimitry Andric << ":\n"; 480349cc55cSDimitry Andric continue; 481349cc55cSDimitry Andric } 482349cc55cSDimitry Andric 483349cc55cSDimitry Andric if (P.first->second->getIRName() != Def->getIRName()) 484349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different IRName"); 485349cc55cSDimitry Andric else if (P.first->second->getManualCodegen() != Def->getManualCodegen()) 486349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different ManualCodegen"); 48781ad6265SDimitry Andric else if (P.first->second->isMasked() != Def->isMasked()) 48881ad6265SDimitry Andric PrintFatalError("Builtin with same name has different isMasked"); 489349cc55cSDimitry Andric else if (P.first->second->hasVL() != Def->hasVL()) 49081ad6265SDimitry Andric PrintFatalError("Builtin with same name has different hasVL"); 49181ad6265SDimitry Andric else if (P.first->second->getPolicyScheme() != Def->getPolicyScheme()) 49281ad6265SDimitry Andric PrintFatalError("Builtin with same name has different getPolicyScheme"); 493349cc55cSDimitry Andric else if (P.first->second->getIntrinsicTypes() != Def->getIntrinsicTypes()) 494349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different IntrinsicTypes"); 495fe6060f1SDimitry Andric } 49681ad6265SDimitry Andric emitCodeGenSwitchBody(Defs.back().get(), OS); 497fe6060f1SDimitry Andric OS << "\n"; 498fe6060f1SDimitry Andric } 499fe6060f1SDimitry Andric 500fe6060f1SDimitry Andric void RVVEmitter::createRVVIntrinsics( 501972a253aSDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> &Out, 502972a253aSDimitry Andric std::vector<SemaRecord> *SemaRecords) { 503fe6060f1SDimitry Andric std::vector<Record *> RV = Records.getAllDerivedDefinitions("RVVBuiltin"); 504fe6060f1SDimitry Andric for (auto *R : RV) { 505fe6060f1SDimitry Andric StringRef Name = R->getValueAsString("Name"); 506fe6060f1SDimitry Andric StringRef SuffixProto = R->getValueAsString("Suffix"); 50781ad6265SDimitry Andric StringRef OverloadedName = R->getValueAsString("OverloadedName"); 50881ad6265SDimitry Andric StringRef OverloadedSuffixProto = R->getValueAsString("OverloadedSuffix"); 509fe6060f1SDimitry Andric StringRef Prototypes = R->getValueAsString("Prototype"); 510fe6060f1SDimitry Andric StringRef TypeRange = R->getValueAsString("TypeRange"); 51181ad6265SDimitry Andric bool HasMasked = R->getValueAsBit("HasMasked"); 512fe6060f1SDimitry Andric bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand"); 513fe6060f1SDimitry Andric bool HasVL = R->getValueAsBit("HasVL"); 514972a253aSDimitry Andric Record *MPSRecord = R->getValueAsDef("MaskedPolicyScheme"); 515972a253aSDimitry Andric auto MaskedPolicyScheme = 516972a253aSDimitry Andric static_cast<PolicyScheme>(MPSRecord->getValueAsInt("Value")); 517972a253aSDimitry Andric Record *UMPSRecord = R->getValueAsDef("UnMaskedPolicyScheme"); 518972a253aSDimitry Andric auto UnMaskedPolicyScheme = 519972a253aSDimitry Andric static_cast<PolicyScheme>(UMPSRecord->getValueAsInt("Value")); 520fe6060f1SDimitry Andric std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL"); 521bdd1243dSDimitry Andric bool HasTailPolicy = R->getValueAsBit("HasTailPolicy"); 522bdd1243dSDimitry Andric bool HasMaskPolicy = R->getValueAsBit("HasMaskPolicy"); 523bdd1243dSDimitry Andric bool SupportOverloading = R->getValueAsBit("SupportOverloading"); 52481ad6265SDimitry Andric bool HasBuiltinAlias = R->getValueAsBit("HasBuiltinAlias"); 525fe6060f1SDimitry Andric StringRef ManualCodegen = R->getValueAsString("ManualCodegen"); 526fe6060f1SDimitry Andric std::vector<int64_t> IntrinsicTypes = 527fe6060f1SDimitry Andric R->getValueAsListOfInts("IntrinsicTypes"); 52804eeddc0SDimitry Andric std::vector<StringRef> RequiredFeatures = 52904eeddc0SDimitry Andric R->getValueAsListOfStrings("RequiredFeatures"); 530fe6060f1SDimitry Andric StringRef IRName = R->getValueAsString("IRName"); 53181ad6265SDimitry Andric StringRef MaskedIRName = R->getValueAsString("MaskedIRName"); 532fe6060f1SDimitry Andric unsigned NF = R->getValueAsInt("NF"); 53306c3fb27SDimitry Andric bool IsTuple = R->getValueAsBit("IsTuple"); 53406c3fb27SDimitry Andric bool HasFRMRoundModeOp = R->getValueAsBit("HasFRMRoundModeOp"); 535fe6060f1SDimitry Andric 5361ac55f4cSDimitry Andric const Policy DefaultPolicy; 537bdd1243dSDimitry Andric SmallVector<Policy> SupportedUnMaskedPolicies = 5381ac55f4cSDimitry Andric RVVIntrinsic::getSupportedUnMaskedPolicies(); 539bdd1243dSDimitry Andric SmallVector<Policy> SupportedMaskedPolicies = 540bdd1243dSDimitry Andric RVVIntrinsic::getSupportedMaskedPolicies(HasTailPolicy, HasMaskPolicy); 541bdd1243dSDimitry Andric 542fe6060f1SDimitry Andric // Parse prototype and create a list of primitive type with transformers 54381ad6265SDimitry Andric // (operand) in Prototype. Prototype[0] is output operand. 544972a253aSDimitry Andric SmallVector<PrototypeDescriptor> BasicPrototype = 545972a253aSDimitry Andric parsePrototypes(Prototypes); 54681ad6265SDimitry Andric 54781ad6265SDimitry Andric SmallVector<PrototypeDescriptor> SuffixDesc = parsePrototypes(SuffixProto); 54881ad6265SDimitry Andric SmallVector<PrototypeDescriptor> OverloadedSuffixDesc = 54981ad6265SDimitry Andric parsePrototypes(OverloadedSuffixProto); 550fe6060f1SDimitry Andric 551fe6060f1SDimitry Andric // Compute Builtin types 552972a253aSDimitry Andric auto Prototype = RVVIntrinsic::computeBuiltinTypes( 553bdd1243dSDimitry Andric BasicPrototype, /*IsMasked=*/false, 554bdd1243dSDimitry Andric /*HasMaskedOffOperand=*/false, HasVL, NF, UnMaskedPolicyScheme, 55506c3fb27SDimitry Andric DefaultPolicy, IsTuple); 55606c3fb27SDimitry Andric llvm::SmallVector<PrototypeDescriptor> MaskedPrototype; 55706c3fb27SDimitry Andric if (HasMasked) 55806c3fb27SDimitry Andric MaskedPrototype = RVVIntrinsic::computeBuiltinTypes( 559bdd1243dSDimitry Andric BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, NF, 56006c3fb27SDimitry Andric MaskedPolicyScheme, DefaultPolicy, IsTuple); 561fe6060f1SDimitry Andric 562fe6060f1SDimitry Andric // Create Intrinsics for each type and LMUL. 563fe6060f1SDimitry Andric for (char I : TypeRange) { 564fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULList) { 56581ad6265SDimitry Andric BasicType BT = ParseBasicType(I); 566bdd1243dSDimitry Andric std::optional<RVVTypes> Types = 567bdd1243dSDimitry Andric TypeCache.computeTypes(BT, Log2LMUL, NF, Prototype); 568fe6060f1SDimitry Andric // Ignored to create new intrinsic if there are any illegal types. 56981ad6265SDimitry Andric if (!Types) 570fe6060f1SDimitry Andric continue; 571fe6060f1SDimitry Andric 572bdd1243dSDimitry Andric auto SuffixStr = 573bdd1243dSDimitry Andric RVVIntrinsic::getSuffixStr(TypeCache, BT, Log2LMUL, SuffixDesc); 574bdd1243dSDimitry Andric auto OverloadedSuffixStr = RVVIntrinsic::getSuffixStr( 575bdd1243dSDimitry Andric TypeCache, BT, Log2LMUL, OverloadedSuffixDesc); 57681ad6265SDimitry Andric // Create a unmasked intrinsic 577fe6060f1SDimitry Andric Out.push_back(std::make_unique<RVVIntrinsic>( 57881ad6265SDimitry Andric Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName, 57981ad6265SDimitry Andric /*IsMasked=*/false, /*HasMaskedOffOperand=*/false, HasVL, 580bdd1243dSDimitry Andric UnMaskedPolicyScheme, SupportOverloading, HasBuiltinAlias, 581bdd1243dSDimitry Andric ManualCodegen, *Types, IntrinsicTypes, RequiredFeatures, NF, 58206c3fb27SDimitry Andric DefaultPolicy, HasFRMRoundModeOp)); 583bdd1243dSDimitry Andric if (UnMaskedPolicyScheme != PolicyScheme::SchemeNone) 584bdd1243dSDimitry Andric for (auto P : SupportedUnMaskedPolicies) { 585bdd1243dSDimitry Andric SmallVector<PrototypeDescriptor> PolicyPrototype = 586bdd1243dSDimitry Andric RVVIntrinsic::computeBuiltinTypes( 587bdd1243dSDimitry Andric BasicPrototype, /*IsMasked=*/false, 588bdd1243dSDimitry Andric /*HasMaskedOffOperand=*/false, HasVL, NF, 58906c3fb27SDimitry Andric UnMaskedPolicyScheme, P, IsTuple); 590bdd1243dSDimitry Andric std::optional<RVVTypes> PolicyTypes = 591bdd1243dSDimitry Andric TypeCache.computeTypes(BT, Log2LMUL, NF, PolicyPrototype); 592bdd1243dSDimitry Andric Out.push_back(std::make_unique<RVVIntrinsic>( 593bdd1243dSDimitry Andric Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName, 594bdd1243dSDimitry Andric /*IsMask=*/false, /*HasMaskedOffOperand=*/false, HasVL, 595bdd1243dSDimitry Andric UnMaskedPolicyScheme, SupportOverloading, HasBuiltinAlias, 596bdd1243dSDimitry Andric ManualCodegen, *PolicyTypes, IntrinsicTypes, RequiredFeatures, 59706c3fb27SDimitry Andric NF, P, HasFRMRoundModeOp)); 598bdd1243dSDimitry Andric } 599bdd1243dSDimitry Andric if (!HasMasked) 600bdd1243dSDimitry Andric continue; 60181ad6265SDimitry Andric // Create a masked intrinsic 602bdd1243dSDimitry Andric std::optional<RVVTypes> MaskTypes = 603bdd1243dSDimitry Andric TypeCache.computeTypes(BT, Log2LMUL, NF, MaskedPrototype); 604bdd1243dSDimitry Andric Out.push_back(std::make_unique<RVVIntrinsic>( 605bdd1243dSDimitry Andric Name, SuffixStr, OverloadedName, OverloadedSuffixStr, MaskedIRName, 606bdd1243dSDimitry Andric /*IsMasked=*/true, HasMaskedOffOperand, HasVL, MaskedPolicyScheme, 607bdd1243dSDimitry Andric SupportOverloading, HasBuiltinAlias, ManualCodegen, *MaskTypes, 60806c3fb27SDimitry Andric IntrinsicTypes, RequiredFeatures, NF, DefaultPolicy, 60906c3fb27SDimitry Andric HasFRMRoundModeOp)); 610bdd1243dSDimitry Andric if (MaskedPolicyScheme == PolicyScheme::SchemeNone) 611bdd1243dSDimitry Andric continue; 612bdd1243dSDimitry Andric for (auto P : SupportedMaskedPolicies) { 613bdd1243dSDimitry Andric SmallVector<PrototypeDescriptor> PolicyPrototype = 614bdd1243dSDimitry Andric RVVIntrinsic::computeBuiltinTypes( 615bdd1243dSDimitry Andric BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, 61606c3fb27SDimitry Andric NF, MaskedPolicyScheme, P, IsTuple); 617bdd1243dSDimitry Andric std::optional<RVVTypes> PolicyTypes = 618bdd1243dSDimitry Andric TypeCache.computeTypes(BT, Log2LMUL, NF, PolicyPrototype); 619fe6060f1SDimitry Andric Out.push_back(std::make_unique<RVVIntrinsic>( 62081ad6265SDimitry Andric Name, SuffixStr, OverloadedName, OverloadedSuffixStr, 621bdd1243dSDimitry Andric MaskedIRName, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, 622bdd1243dSDimitry Andric MaskedPolicyScheme, SupportOverloading, HasBuiltinAlias, 623bdd1243dSDimitry Andric ManualCodegen, *PolicyTypes, IntrinsicTypes, RequiredFeatures, NF, 62406c3fb27SDimitry Andric P, HasFRMRoundModeOp)); 625fe6060f1SDimitry Andric } 626bdd1243dSDimitry Andric } // End for Log2LMULList 627bdd1243dSDimitry Andric } // End for TypeRange 628972a253aSDimitry Andric 629972a253aSDimitry Andric // We don't emit vsetvli and vsetvlimax for SemaRecord. 630972a253aSDimitry Andric // They are written in riscv_vector.td and will emit those marco define in 631972a253aSDimitry Andric // riscv_vector.h 632972a253aSDimitry Andric if (Name == "vsetvli" || Name == "vsetvlimax") 633972a253aSDimitry Andric continue; 634972a253aSDimitry Andric 635972a253aSDimitry Andric if (!SemaRecords) 636972a253aSDimitry Andric continue; 637972a253aSDimitry Andric 638972a253aSDimitry Andric // Create SemaRecord 639972a253aSDimitry Andric SemaRecord SR; 640972a253aSDimitry Andric SR.Name = Name.str(); 641972a253aSDimitry Andric SR.OverloadedName = OverloadedName.str(); 642972a253aSDimitry Andric BasicType TypeRangeMask = BasicType::Unknown; 643972a253aSDimitry Andric for (char I : TypeRange) 644972a253aSDimitry Andric TypeRangeMask |= ParseBasicType(I); 645972a253aSDimitry Andric 646972a253aSDimitry Andric SR.TypeRangeMask = static_cast<unsigned>(TypeRangeMask); 647972a253aSDimitry Andric 648972a253aSDimitry Andric unsigned Log2LMULMask = 0; 649972a253aSDimitry Andric for (int Log2LMUL : Log2LMULList) 650972a253aSDimitry Andric Log2LMULMask |= 1 << (Log2LMUL + 3); 651972a253aSDimitry Andric 652972a253aSDimitry Andric SR.Log2LMULMask = Log2LMULMask; 653972a253aSDimitry Andric 654972a253aSDimitry Andric SR.RequiredExtensions = 0; 655972a253aSDimitry Andric for (auto RequiredFeature : RequiredFeatures) { 656*cb14a3feSDimitry Andric RVVRequire RequireExt = 657*cb14a3feSDimitry Andric StringSwitch<RVVRequire>(RequiredFeature) 658972a253aSDimitry Andric .Case("RV64", RVV_REQ_RV64) 6595f757f3fSDimitry Andric .Case("ZvfhminOrZvfh", RVV_REQ_ZvfhminOrZvfh) 66006c3fb27SDimitry Andric .Case("Xsfvcp", RVV_REQ_Xsfvcp) 6615f757f3fSDimitry Andric .Case("Xsfvfnrclipxfqf", RVV_REQ_Xsfvfnrclipxfqf) 6625f757f3fSDimitry Andric .Case("Xsfvfwmaccqqq", RVV_REQ_Xsfvfwmaccqqq) 6635f757f3fSDimitry Andric .Case("Xsfvqmaccdod", RVV_REQ_Xsfvqmaccdod) 6645f757f3fSDimitry Andric .Case("Xsfvqmaccqoq", RVV_REQ_Xsfvqmaccqoq) 6655f757f3fSDimitry Andric .Case("Zvbb", RVV_REQ_Zvbb) 6665f757f3fSDimitry Andric .Case("Zvbc", RVV_REQ_Zvbc) 6675f757f3fSDimitry Andric .Case("Zvkb", RVV_REQ_Zvkb) 6685f757f3fSDimitry Andric .Case("Zvkg", RVV_REQ_Zvkg) 6695f757f3fSDimitry Andric .Case("Zvkned", RVV_REQ_Zvkned) 6705f757f3fSDimitry Andric .Case("Zvknha", RVV_REQ_Zvknha) 6715f757f3fSDimitry Andric .Case("Zvknhb", RVV_REQ_Zvknhb) 6725f757f3fSDimitry Andric .Case("Zvksed", RVV_REQ_Zvksed) 6735f757f3fSDimitry Andric .Case("Zvksh", RVV_REQ_Zvksh) 674*cb14a3feSDimitry Andric .Case("Experimental", RVV_REQ_Experimental) 675972a253aSDimitry Andric .Default(RVV_REQ_None); 676972a253aSDimitry Andric assert(RequireExt != RVV_REQ_None && "Unrecognized required feature?"); 677972a253aSDimitry Andric SR.RequiredExtensions |= RequireExt; 678972a253aSDimitry Andric } 679972a253aSDimitry Andric 680972a253aSDimitry Andric SR.NF = NF; 681972a253aSDimitry Andric SR.HasMasked = HasMasked; 682972a253aSDimitry Andric SR.HasVL = HasVL; 683972a253aSDimitry Andric SR.HasMaskedOffOperand = HasMaskedOffOperand; 684bdd1243dSDimitry Andric SR.HasTailPolicy = HasTailPolicy; 685bdd1243dSDimitry Andric SR.HasMaskPolicy = HasMaskPolicy; 686bdd1243dSDimitry Andric SR.UnMaskedPolicyScheme = static_cast<uint8_t>(UnMaskedPolicyScheme); 687bdd1243dSDimitry Andric SR.MaskedPolicyScheme = static_cast<uint8_t>(MaskedPolicyScheme); 688972a253aSDimitry Andric SR.Prototype = std::move(BasicPrototype); 689972a253aSDimitry Andric SR.Suffix = parsePrototypes(SuffixProto); 690972a253aSDimitry Andric SR.OverloadedSuffix = parsePrototypes(OverloadedSuffixProto); 69106c3fb27SDimitry Andric SR.IsTuple = IsTuple; 69206c3fb27SDimitry Andric SR.HasFRMRoundModeOp = HasFRMRoundModeOp; 693972a253aSDimitry Andric 694972a253aSDimitry Andric SemaRecords->push_back(SR); 695fe6060f1SDimitry Andric } 696fe6060f1SDimitry Andric } 697fe6060f1SDimitry Andric 69881ad6265SDimitry Andric void RVVEmitter::printHeaderCode(raw_ostream &OS) { 699349cc55cSDimitry Andric std::vector<Record *> RVVHeaders = 700349cc55cSDimitry Andric Records.getAllDerivedDefinitions("RVVHeader"); 701349cc55cSDimitry Andric for (auto *R : RVVHeaders) { 702349cc55cSDimitry Andric StringRef HeaderCodeStr = R->getValueAsString("HeaderCode"); 703349cc55cSDimitry Andric OS << HeaderCodeStr.str(); 704349cc55cSDimitry Andric } 705349cc55cSDimitry Andric } 706349cc55cSDimitry Andric 707972a253aSDimitry Andric void RVVEmitter::createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out, 708972a253aSDimitry Andric SemaSignatureTable &SST, 709972a253aSDimitry Andric ArrayRef<SemaRecord> SemaRecords) { 710972a253aSDimitry Andric SST.init(SemaRecords); 711972a253aSDimitry Andric 712972a253aSDimitry Andric for (const auto &SR : SemaRecords) { 713972a253aSDimitry Andric Out.emplace_back(RVVIntrinsicRecord()); 714972a253aSDimitry Andric RVVIntrinsicRecord &R = Out.back(); 715972a253aSDimitry Andric R.Name = SR.Name.c_str(); 716972a253aSDimitry Andric R.OverloadedName = SR.OverloadedName.c_str(); 717972a253aSDimitry Andric R.PrototypeIndex = SST.getIndex(SR.Prototype); 718972a253aSDimitry Andric R.SuffixIndex = SST.getIndex(SR.Suffix); 719972a253aSDimitry Andric R.OverloadedSuffixIndex = SST.getIndex(SR.OverloadedSuffix); 720972a253aSDimitry Andric R.PrototypeLength = SR.Prototype.size(); 721972a253aSDimitry Andric R.SuffixLength = SR.Suffix.size(); 722972a253aSDimitry Andric R.OverloadedSuffixSize = SR.OverloadedSuffix.size(); 723972a253aSDimitry Andric R.RequiredExtensions = SR.RequiredExtensions; 724972a253aSDimitry Andric R.TypeRangeMask = SR.TypeRangeMask; 725972a253aSDimitry Andric R.Log2LMULMask = SR.Log2LMULMask; 726972a253aSDimitry Andric R.NF = SR.NF; 727972a253aSDimitry Andric R.HasMasked = SR.HasMasked; 728972a253aSDimitry Andric R.HasVL = SR.HasVL; 729972a253aSDimitry Andric R.HasMaskedOffOperand = SR.HasMaskedOffOperand; 730bdd1243dSDimitry Andric R.HasTailPolicy = SR.HasTailPolicy; 731bdd1243dSDimitry Andric R.HasMaskPolicy = SR.HasMaskPolicy; 732bdd1243dSDimitry Andric R.UnMaskedPolicyScheme = SR.UnMaskedPolicyScheme; 733bdd1243dSDimitry Andric R.MaskedPolicyScheme = SR.MaskedPolicyScheme; 73406c3fb27SDimitry Andric R.IsTuple = SR.IsTuple; 73506c3fb27SDimitry Andric R.HasFRMRoundModeOp = SR.HasFRMRoundModeOp; 736972a253aSDimitry Andric 737972a253aSDimitry Andric assert(R.PrototypeIndex != 738972a253aSDimitry Andric static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 739972a253aSDimitry Andric assert(R.SuffixIndex != 740972a253aSDimitry Andric static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 741972a253aSDimitry Andric assert(R.OverloadedSuffixIndex != 742972a253aSDimitry Andric static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 743fe6060f1SDimitry Andric } 744fe6060f1SDimitry Andric } 745fe6060f1SDimitry Andric 746972a253aSDimitry Andric void RVVEmitter::createSema(raw_ostream &OS) { 747972a253aSDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 748972a253aSDimitry Andric std::vector<RVVIntrinsicRecord> RVVIntrinsicRecords; 749972a253aSDimitry Andric SemaSignatureTable SST; 750972a253aSDimitry Andric std::vector<SemaRecord> SemaRecords; 751972a253aSDimitry Andric 752972a253aSDimitry Andric createRVVIntrinsics(Defs, &SemaRecords); 753972a253aSDimitry Andric 754972a253aSDimitry Andric createRVVIntrinsicRecords(RVVIntrinsicRecords, SST, SemaRecords); 755972a253aSDimitry Andric 756972a253aSDimitry Andric // Emit signature table for SemaRISCVVectorLookup.cpp. 757972a253aSDimitry Andric OS << "#ifdef DECL_SIGNATURE_TABLE\n"; 758972a253aSDimitry Andric SST.print(OS); 759972a253aSDimitry Andric OS << "#endif\n"; 760972a253aSDimitry Andric 761972a253aSDimitry Andric // Emit RVVIntrinsicRecords for SemaRISCVVectorLookup.cpp. 762972a253aSDimitry Andric OS << "#ifdef DECL_INTRINSIC_RECORDS\n"; 763972a253aSDimitry Andric for (const RVVIntrinsicRecord &Record : RVVIntrinsicRecords) 764972a253aSDimitry Andric OS << Record; 765972a253aSDimitry Andric OS << "#endif\n"; 766fe6060f1SDimitry Andric } 767fe6060f1SDimitry Andric 768fe6060f1SDimitry Andric namespace clang { 769fe6060f1SDimitry Andric void EmitRVVHeader(RecordKeeper &Records, raw_ostream &OS) { 770fe6060f1SDimitry Andric RVVEmitter(Records).createHeader(OS); 771fe6060f1SDimitry Andric } 772fe6060f1SDimitry Andric 773fe6060f1SDimitry Andric void EmitRVVBuiltins(RecordKeeper &Records, raw_ostream &OS) { 774fe6060f1SDimitry Andric RVVEmitter(Records).createBuiltins(OS); 775fe6060f1SDimitry Andric } 776fe6060f1SDimitry Andric 777fe6060f1SDimitry Andric void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 778fe6060f1SDimitry Andric RVVEmitter(Records).createCodeGen(OS); 779fe6060f1SDimitry Andric } 780fe6060f1SDimitry Andric 781972a253aSDimitry Andric void EmitRVVBuiltinSema(RecordKeeper &Records, raw_ostream &OS) { 782972a253aSDimitry Andric RVVEmitter(Records).createSema(OS); 783972a253aSDimitry Andric } 784972a253aSDimitry Andric 785fe6060f1SDimitry Andric } // End namespace clang 786