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. 49972a253aSDimitry Andric unsigned 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; 68*06c3fb27SDimitry Andric bool HasFRMRoundModeOp : 1; 69*06c3fb27SDimitry 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; 15481ad6265SDimitry Andric 155fe6060f1SDimitry Andric default: 15681ad6265SDimitry Andric return BasicType::Unknown; 157fe6060f1SDimitry Andric } 158fe6060f1SDimitry Andric } 159fe6060f1SDimitry Andric 160*06c3fb27SDimitry Andric static VectorTypeModifier getTupleVTM(unsigned NF) { 161*06c3fb27SDimitry Andric assert(2 <= NF && NF <= 8 && "2 <= NF <= 8"); 162*06c3fb27SDimitry Andric return static_cast<VectorTypeModifier>( 163*06c3fb27SDimitry Andric static_cast<uint8_t>(VectorTypeModifier::Tuple2) + (NF - 2)); 164*06c3fb27SDimitry Andric } 165*06c3fb27SDimitry Andric 16681ad6265SDimitry Andric void emitCodeGenSwitchBody(const RVVIntrinsic *RVVI, raw_ostream &OS) { 16781ad6265SDimitry Andric if (!RVVI->getIRName().empty()) 16881ad6265SDimitry Andric OS << " ID = Intrinsic::riscv_" + RVVI->getIRName() + ";\n"; 16981ad6265SDimitry Andric if (RVVI->getNF() >= 2) 17081ad6265SDimitry Andric OS << " NF = " + utostr(RVVI->getNF()) + ";\n"; 171bdd1243dSDimitry Andric 172bdd1243dSDimitry Andric OS << " PolicyAttrs = " << RVVI->getPolicyAttrsBits() << ";\n"; 173bdd1243dSDimitry Andric 17481ad6265SDimitry Andric if (RVVI->hasManualCodegen()) { 175bdd1243dSDimitry Andric OS << "IsMasked = " << (RVVI->isMasked() ? "true" : "false") << ";\n"; 17681ad6265SDimitry Andric OS << RVVI->getManualCodegen(); 177fe6060f1SDimitry Andric OS << "break;\n"; 178fe6060f1SDimitry Andric return; 179fe6060f1SDimitry Andric } 180fe6060f1SDimitry Andric 181753f127fSDimitry Andric // Cast pointer operand of vector load intrinsic. 182753f127fSDimitry Andric for (const auto &I : enumerate(RVVI->getInputTypes())) { 183753f127fSDimitry Andric if (I.value()->isPointer()) { 184753f127fSDimitry Andric assert(RVVI->getIntrinsicTypes().front() == -1 && 185753f127fSDimitry Andric "RVVI should be vector load intrinsic."); 186753f127fSDimitry Andric OS << " Ops[" << I.index() << "] = Builder.CreateBitCast(Ops["; 187753f127fSDimitry Andric OS << I.index() << "], ResultType->getPointerTo());\n"; 188753f127fSDimitry Andric } 189753f127fSDimitry Andric } 190753f127fSDimitry Andric 19181ad6265SDimitry Andric if (RVVI->isMasked()) { 19281ad6265SDimitry Andric if (RVVI->hasVL()) { 193fe6060f1SDimitry Andric OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n"; 19481ad6265SDimitry Andric if (RVVI->hasPolicyOperand()) 195349cc55cSDimitry Andric OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType()," 196bdd1243dSDimitry Andric " PolicyAttrs));\n"; 197bdd1243dSDimitry Andric if (RVVI->hasMaskedOffOperand() && RVVI->getPolicyAttrs().isTAMAPolicy()) 198bdd1243dSDimitry Andric OS << " Ops.insert(Ops.begin(), " 199bdd1243dSDimitry Andric "llvm::PoisonValue::get(ResultType));\n"; 200bdd1243dSDimitry Andric // Masked reduction cases. 201bdd1243dSDimitry Andric if (!RVVI->hasMaskedOffOperand() && RVVI->hasPassthruOperand() && 202bdd1243dSDimitry Andric RVVI->getPolicyAttrs().isTAMAPolicy()) 203bdd1243dSDimitry Andric OS << " Ops.insert(Ops.begin(), " 204bdd1243dSDimitry Andric "llvm::PoisonValue::get(ResultType));\n"; 205fe6060f1SDimitry Andric } else { 206fe6060f1SDimitry Andric OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n"; 207fe6060f1SDimitry Andric } 20881ad6265SDimitry Andric } else { 20981ad6265SDimitry Andric if (RVVI->hasPolicyOperand()) 21081ad6265SDimitry Andric OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(), " 211bdd1243dSDimitry Andric "PolicyAttrs));\n"; 212bdd1243dSDimitry Andric else if (RVVI->hasPassthruOperand() && RVVI->getPolicyAttrs().isTAPolicy()) 213bdd1243dSDimitry Andric OS << " Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));\n"; 214fe6060f1SDimitry Andric } 215fe6060f1SDimitry Andric 216fe6060f1SDimitry Andric OS << " IntrinsicTypes = {"; 217fe6060f1SDimitry Andric ListSeparator LS; 21881ad6265SDimitry Andric for (const auto &Idx : RVVI->getIntrinsicTypes()) { 219fe6060f1SDimitry Andric if (Idx == -1) 220fe6060f1SDimitry Andric OS << LS << "ResultType"; 221fe6060f1SDimitry Andric else 222fe6060f1SDimitry Andric OS << LS << "Ops[" << Idx << "]->getType()"; 223fe6060f1SDimitry Andric } 224fe6060f1SDimitry Andric 225fe6060f1SDimitry Andric // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is 226fe6060f1SDimitry Andric // always last operand. 22781ad6265SDimitry Andric if (RVVI->hasVL()) 228fe6060f1SDimitry Andric OS << ", Ops.back()->getType()"; 229fe6060f1SDimitry Andric OS << "};\n"; 230fe6060f1SDimitry Andric OS << " break;\n"; 231fe6060f1SDimitry Andric } 232fe6060f1SDimitry Andric 233972a253aSDimitry Andric //===----------------------------------------------------------------------===// 234972a253aSDimitry Andric // SemaSignatureTable implementation 235972a253aSDimitry Andric //===----------------------------------------------------------------------===// 236972a253aSDimitry Andric void SemaSignatureTable::init(ArrayRef<SemaRecord> SemaRecords) { 237972a253aSDimitry Andric // Sort signature entries by length, let longer signature insert first, to 238972a253aSDimitry Andric // make it more possible to reuse table entries, that can reduce ~10% table 239972a253aSDimitry Andric // size. 240972a253aSDimitry Andric struct Compare { 241972a253aSDimitry Andric bool operator()(const SmallVector<PrototypeDescriptor> &A, 242972a253aSDimitry Andric const SmallVector<PrototypeDescriptor> &B) const { 243972a253aSDimitry Andric if (A.size() != B.size()) 244972a253aSDimitry Andric return A.size() > B.size(); 245972a253aSDimitry Andric 246972a253aSDimitry Andric size_t Len = A.size(); 247972a253aSDimitry Andric for (size_t i = 0; i < Len; ++i) { 248972a253aSDimitry Andric if (A[i] != B[i]) 249972a253aSDimitry Andric return A[i] < B[i]; 250fe6060f1SDimitry Andric } 251fe6060f1SDimitry Andric 252972a253aSDimitry Andric return false; 253fe6060f1SDimitry Andric } 254972a253aSDimitry Andric }; 255972a253aSDimitry Andric 256972a253aSDimitry Andric std::set<SmallVector<PrototypeDescriptor>, Compare> Signatures; 257972a253aSDimitry Andric auto InsertToSignatureSet = 258972a253aSDimitry Andric [&](const SmallVector<PrototypeDescriptor> &Signature) { 259972a253aSDimitry Andric if (Signature.empty()) 260972a253aSDimitry Andric return; 261972a253aSDimitry Andric 262972a253aSDimitry Andric Signatures.insert(Signature); 263972a253aSDimitry Andric }; 264972a253aSDimitry Andric 265972a253aSDimitry Andric assert(!SemaRecords.empty()); 266972a253aSDimitry Andric 267972a253aSDimitry Andric llvm::for_each(SemaRecords, [&](const SemaRecord &SR) { 268972a253aSDimitry Andric InsertToSignatureSet(SR.Prototype); 269972a253aSDimitry Andric InsertToSignatureSet(SR.Suffix); 270972a253aSDimitry Andric InsertToSignatureSet(SR.OverloadedSuffix); 271972a253aSDimitry Andric }); 272972a253aSDimitry Andric 273972a253aSDimitry Andric llvm::for_each(Signatures, [this](auto &Sig) { 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. 292972a253aSDimitry 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 } 374*06c3fb27SDimitry Andric for (int NF = 2; NF <= 8; ++NF) { 375*06c3fb27SDimitry Andric auto TupleT = TypeCache.computeType( 376*06c3fb27SDimitry Andric BT, Log2LMUL, 377*06c3fb27SDimitry Andric PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF), 378*06c3fb27SDimitry Andric TypeModifier::SignedInteger)); 379*06c3fb27SDimitry Andric auto TupleUT = TypeCache.computeType( 380*06c3fb27SDimitry Andric BT, Log2LMUL, 381*06c3fb27SDimitry Andric PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF), 382*06c3fb27SDimitry Andric TypeModifier::UnsignedInteger)); 383*06c3fb27SDimitry Andric if (TupleT) 384*06c3fb27SDimitry Andric printType(*TupleT); 385*06c3fb27SDimitry Andric if (TupleUT) 386*06c3fb27SDimitry Andric printType(*TupleUT); 387fe6060f1SDimitry Andric } 388fe6060f1SDimitry Andric } 389fe6060f1SDimitry Andric } 390fe6060f1SDimitry Andric 391*06c3fb27SDimitry Andric for (BasicType BT : 392*06c3fb27SDimitry Andric {BasicType::Float16, BasicType::Float32, BasicType::Float64}) { 393fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 394*06c3fb27SDimitry Andric auto T = TypeCache.computeType(BT, Log2LMUL, PrototypeDescriptor::Vector); 39581ad6265SDimitry Andric if (T) 396bdd1243dSDimitry Andric printType(*T); 397*06c3fb27SDimitry Andric for (int NF = 2; NF <= 8; ++NF) { 398*06c3fb27SDimitry Andric auto TupleT = TypeCache.computeType( 399*06c3fb27SDimitry Andric BT, Log2LMUL, 400*06c3fb27SDimitry Andric PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF), 401*06c3fb27SDimitry Andric TypeModifier::Float)); 402*06c3fb27SDimitry Andric if (TupleT) 403*06c3fb27SDimitry Andric printType(*TupleT); 404fe6060f1SDimitry Andric } 405fe6060f1SDimitry Andric } 406*06c3fb27SDimitry 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"); 485349cc55cSDimitry Andric else if (P.first->second->getNF() != Def->getNF()) 486349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different NF"); 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"); 533*06c3fb27SDimitry Andric bool IsTuple = R->getValueAsBit("IsTuple"); 534*06c3fb27SDimitry 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, 555*06c3fb27SDimitry Andric DefaultPolicy, IsTuple); 556*06c3fb27SDimitry Andric llvm::SmallVector<PrototypeDescriptor> MaskedPrototype; 557*06c3fb27SDimitry Andric if (HasMasked) 558*06c3fb27SDimitry Andric MaskedPrototype = RVVIntrinsic::computeBuiltinTypes( 559bdd1243dSDimitry Andric BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, NF, 560*06c3fb27SDimitry 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, 582*06c3fb27SDimitry 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, 589*06c3fb27SDimitry 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, 597*06c3fb27SDimitry 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, 608*06c3fb27SDimitry Andric IntrinsicTypes, RequiredFeatures, NF, DefaultPolicy, 609*06c3fb27SDimitry 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, 616*06c3fb27SDimitry 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, 624*06c3fb27SDimitry 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) { 656972a253aSDimitry Andric RVVRequire RequireExt = StringSwitch<RVVRequire>(RequiredFeature) 657972a253aSDimitry Andric .Case("RV64", RVV_REQ_RV64) 658*06c3fb27SDimitry Andric .Case("Xsfvcp", RVV_REQ_Xsfvcp) 659972a253aSDimitry Andric .Default(RVV_REQ_None); 660972a253aSDimitry Andric assert(RequireExt != RVV_REQ_None && "Unrecognized required feature?"); 661972a253aSDimitry Andric SR.RequiredExtensions |= RequireExt; 662972a253aSDimitry Andric } 663972a253aSDimitry Andric 664972a253aSDimitry Andric SR.NF = NF; 665972a253aSDimitry Andric SR.HasMasked = HasMasked; 666972a253aSDimitry Andric SR.HasVL = HasVL; 667972a253aSDimitry Andric SR.HasMaskedOffOperand = HasMaskedOffOperand; 668bdd1243dSDimitry Andric SR.HasTailPolicy = HasTailPolicy; 669bdd1243dSDimitry Andric SR.HasMaskPolicy = HasMaskPolicy; 670bdd1243dSDimitry Andric SR.UnMaskedPolicyScheme = static_cast<uint8_t>(UnMaskedPolicyScheme); 671bdd1243dSDimitry Andric SR.MaskedPolicyScheme = static_cast<uint8_t>(MaskedPolicyScheme); 672972a253aSDimitry Andric SR.Prototype = std::move(BasicPrototype); 673972a253aSDimitry Andric SR.Suffix = parsePrototypes(SuffixProto); 674972a253aSDimitry Andric SR.OverloadedSuffix = parsePrototypes(OverloadedSuffixProto); 675*06c3fb27SDimitry Andric SR.IsTuple = IsTuple; 676*06c3fb27SDimitry Andric SR.HasFRMRoundModeOp = HasFRMRoundModeOp; 677972a253aSDimitry Andric 678972a253aSDimitry Andric SemaRecords->push_back(SR); 679fe6060f1SDimitry Andric } 680fe6060f1SDimitry Andric } 681fe6060f1SDimitry Andric 68281ad6265SDimitry Andric void RVVEmitter::printHeaderCode(raw_ostream &OS) { 683349cc55cSDimitry Andric std::vector<Record *> RVVHeaders = 684349cc55cSDimitry Andric Records.getAllDerivedDefinitions("RVVHeader"); 685349cc55cSDimitry Andric for (auto *R : RVVHeaders) { 686349cc55cSDimitry Andric StringRef HeaderCodeStr = R->getValueAsString("HeaderCode"); 687349cc55cSDimitry Andric OS << HeaderCodeStr.str(); 688349cc55cSDimitry Andric } 689349cc55cSDimitry Andric } 690349cc55cSDimitry Andric 691972a253aSDimitry Andric void RVVEmitter::createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out, 692972a253aSDimitry Andric SemaSignatureTable &SST, 693972a253aSDimitry Andric ArrayRef<SemaRecord> SemaRecords) { 694972a253aSDimitry Andric SST.init(SemaRecords); 695972a253aSDimitry Andric 696972a253aSDimitry Andric for (const auto &SR : SemaRecords) { 697972a253aSDimitry Andric Out.emplace_back(RVVIntrinsicRecord()); 698972a253aSDimitry Andric RVVIntrinsicRecord &R = Out.back(); 699972a253aSDimitry Andric R.Name = SR.Name.c_str(); 700972a253aSDimitry Andric R.OverloadedName = SR.OverloadedName.c_str(); 701972a253aSDimitry Andric R.PrototypeIndex = SST.getIndex(SR.Prototype); 702972a253aSDimitry Andric R.SuffixIndex = SST.getIndex(SR.Suffix); 703972a253aSDimitry Andric R.OverloadedSuffixIndex = SST.getIndex(SR.OverloadedSuffix); 704972a253aSDimitry Andric R.PrototypeLength = SR.Prototype.size(); 705972a253aSDimitry Andric R.SuffixLength = SR.Suffix.size(); 706972a253aSDimitry Andric R.OverloadedSuffixSize = SR.OverloadedSuffix.size(); 707972a253aSDimitry Andric R.RequiredExtensions = SR.RequiredExtensions; 708972a253aSDimitry Andric R.TypeRangeMask = SR.TypeRangeMask; 709972a253aSDimitry Andric R.Log2LMULMask = SR.Log2LMULMask; 710972a253aSDimitry Andric R.NF = SR.NF; 711972a253aSDimitry Andric R.HasMasked = SR.HasMasked; 712972a253aSDimitry Andric R.HasVL = SR.HasVL; 713972a253aSDimitry Andric R.HasMaskedOffOperand = SR.HasMaskedOffOperand; 714bdd1243dSDimitry Andric R.HasTailPolicy = SR.HasTailPolicy; 715bdd1243dSDimitry Andric R.HasMaskPolicy = SR.HasMaskPolicy; 716bdd1243dSDimitry Andric R.UnMaskedPolicyScheme = SR.UnMaskedPolicyScheme; 717bdd1243dSDimitry Andric R.MaskedPolicyScheme = SR.MaskedPolicyScheme; 718*06c3fb27SDimitry Andric R.IsTuple = SR.IsTuple; 719*06c3fb27SDimitry Andric R.HasFRMRoundModeOp = SR.HasFRMRoundModeOp; 720972a253aSDimitry Andric 721972a253aSDimitry Andric assert(R.PrototypeIndex != 722972a253aSDimitry Andric static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 723972a253aSDimitry Andric assert(R.SuffixIndex != 724972a253aSDimitry Andric static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 725972a253aSDimitry Andric assert(R.OverloadedSuffixIndex != 726972a253aSDimitry Andric static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 727fe6060f1SDimitry Andric } 728fe6060f1SDimitry Andric } 729fe6060f1SDimitry Andric 730972a253aSDimitry Andric void RVVEmitter::createSema(raw_ostream &OS) { 731972a253aSDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 732972a253aSDimitry Andric std::vector<RVVIntrinsicRecord> RVVIntrinsicRecords; 733972a253aSDimitry Andric SemaSignatureTable SST; 734972a253aSDimitry Andric std::vector<SemaRecord> SemaRecords; 735972a253aSDimitry Andric 736972a253aSDimitry Andric createRVVIntrinsics(Defs, &SemaRecords); 737972a253aSDimitry Andric 738972a253aSDimitry Andric createRVVIntrinsicRecords(RVVIntrinsicRecords, SST, SemaRecords); 739972a253aSDimitry Andric 740972a253aSDimitry Andric // Emit signature table for SemaRISCVVectorLookup.cpp. 741972a253aSDimitry Andric OS << "#ifdef DECL_SIGNATURE_TABLE\n"; 742972a253aSDimitry Andric SST.print(OS); 743972a253aSDimitry Andric OS << "#endif\n"; 744972a253aSDimitry Andric 745972a253aSDimitry Andric // Emit RVVIntrinsicRecords for SemaRISCVVectorLookup.cpp. 746972a253aSDimitry Andric OS << "#ifdef DECL_INTRINSIC_RECORDS\n"; 747972a253aSDimitry Andric for (const RVVIntrinsicRecord &Record : RVVIntrinsicRecords) 748972a253aSDimitry Andric OS << Record; 749972a253aSDimitry Andric OS << "#endif\n"; 750fe6060f1SDimitry Andric } 751fe6060f1SDimitry Andric 752fe6060f1SDimitry Andric namespace clang { 753fe6060f1SDimitry Andric void EmitRVVHeader(RecordKeeper &Records, raw_ostream &OS) { 754fe6060f1SDimitry Andric RVVEmitter(Records).createHeader(OS); 755fe6060f1SDimitry Andric } 756fe6060f1SDimitry Andric 757fe6060f1SDimitry Andric void EmitRVVBuiltins(RecordKeeper &Records, raw_ostream &OS) { 758fe6060f1SDimitry Andric RVVEmitter(Records).createBuiltins(OS); 759fe6060f1SDimitry Andric } 760fe6060f1SDimitry Andric 761fe6060f1SDimitry Andric void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 762fe6060f1SDimitry Andric RVVEmitter(Records).createCodeGen(OS); 763fe6060f1SDimitry Andric } 764fe6060f1SDimitry Andric 765972a253aSDimitry Andric void EmitRVVBuiltinSema(RecordKeeper &Records, raw_ostream &OS) { 766972a253aSDimitry Andric RVVEmitter(Records).createSema(OS); 767972a253aSDimitry Andric } 768972a253aSDimitry Andric 769fe6060f1SDimitry Andric } // End namespace clang 770