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 60bdd1243dSDimitry Andric // BitMask for supported policies. 61bdd1243dSDimitry Andric uint16_t PolicyBitMask; 62bdd1243dSDimitry Andric 63972a253aSDimitry Andric // Number of field, large than 1 if it's segment load/store. 64972a253aSDimitry Andric unsigned NF; 65972a253aSDimitry Andric 66972a253aSDimitry Andric bool HasMasked :1; 67972a253aSDimitry Andric bool HasVL :1; 68972a253aSDimitry Andric bool HasMaskedOffOperand :1; 69bdd1243dSDimitry Andric bool HasTailPolicy : 1; 70bdd1243dSDimitry Andric bool HasMaskPolicy : 1; 71bdd1243dSDimitry Andric uint8_t UnMaskedPolicyScheme : 2; 72bdd1243dSDimitry Andric uint8_t MaskedPolicyScheme : 2; 73972a253aSDimitry Andric }; 74972a253aSDimitry Andric 75972a253aSDimitry Andric // Compressed function signature table. 76972a253aSDimitry Andric class SemaSignatureTable { 77972a253aSDimitry Andric private: 78972a253aSDimitry Andric std::vector<PrototypeDescriptor> SignatureTable; 79972a253aSDimitry Andric 80972a253aSDimitry Andric void insert(ArrayRef<PrototypeDescriptor> Signature); 81972a253aSDimitry Andric 82972a253aSDimitry Andric public: 83972a253aSDimitry Andric static constexpr unsigned INVALID_INDEX = ~0U; 84972a253aSDimitry Andric 85972a253aSDimitry Andric // Create compressed signature table from SemaRecords. 86972a253aSDimitry Andric void init(ArrayRef<SemaRecord> SemaRecords); 87972a253aSDimitry Andric 88972a253aSDimitry Andric // Query the Signature, return INVALID_INDEX if not found. 89972a253aSDimitry Andric unsigned getIndex(ArrayRef<PrototypeDescriptor> Signature); 90972a253aSDimitry Andric 91972a253aSDimitry Andric /// Print signature table in RVVHeader Record to \p OS 92972a253aSDimitry Andric void print(raw_ostream &OS); 93972a253aSDimitry Andric }; 94972a253aSDimitry Andric 95fe6060f1SDimitry Andric class RVVEmitter { 96fe6060f1SDimitry Andric private: 97fe6060f1SDimitry Andric RecordKeeper &Records; 98bdd1243dSDimitry Andric RVVTypeCache TypeCache; 99fe6060f1SDimitry Andric 100fe6060f1SDimitry Andric public: 101fe6060f1SDimitry Andric RVVEmitter(RecordKeeper &R) : Records(R) {} 102fe6060f1SDimitry Andric 103fe6060f1SDimitry Andric /// Emit riscv_vector.h 104fe6060f1SDimitry Andric void createHeader(raw_ostream &o); 105fe6060f1SDimitry Andric 106fe6060f1SDimitry Andric /// Emit all the __builtin prototypes and code needed by Sema. 107fe6060f1SDimitry Andric void createBuiltins(raw_ostream &o); 108fe6060f1SDimitry Andric 109fe6060f1SDimitry Andric /// Emit all the information needed to map builtin -> LLVM IR intrinsic. 110fe6060f1SDimitry Andric void createCodeGen(raw_ostream &o); 111fe6060f1SDimitry Andric 112972a253aSDimitry Andric /// Emit all the information needed by SemaRISCVVectorLookup.cpp. 113972a253aSDimitry Andric /// We've large number of intrinsic function for RVV, creating a customized 114972a253aSDimitry Andric /// could speed up the compilation time. 115972a253aSDimitry Andric void createSema(raw_ostream &o); 116972a253aSDimitry Andric 117fe6060f1SDimitry Andric private: 118972a253aSDimitry Andric /// Create all intrinsics and add them to \p Out and SemaRecords. 119972a253aSDimitry Andric void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out, 120972a253aSDimitry Andric std::vector<SemaRecord> *SemaRecords = nullptr); 121972a253aSDimitry Andric /// Create all intrinsic records and SemaSignatureTable from SemaRecords. 122972a253aSDimitry Andric void createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out, 123972a253aSDimitry Andric SemaSignatureTable &SST, 124972a253aSDimitry Andric ArrayRef<SemaRecord> SemaRecords); 125972a253aSDimitry Andric 12681ad6265SDimitry Andric /// Print HeaderCode in RVVHeader Record to \p Out 12781ad6265SDimitry Andric void printHeaderCode(raw_ostream &OS); 128fe6060f1SDimitry Andric }; 129fe6060f1SDimitry Andric 130fe6060f1SDimitry Andric } // namespace 131fe6060f1SDimitry Andric 13281ad6265SDimitry Andric static BasicType ParseBasicType(char c) { 13381ad6265SDimitry Andric switch (c) { 134fe6060f1SDimitry Andric case 'c': 13581ad6265SDimitry Andric return BasicType::Int8; 136fe6060f1SDimitry Andric break; 137fe6060f1SDimitry Andric case 's': 13881ad6265SDimitry Andric return BasicType::Int16; 139fe6060f1SDimitry Andric break; 140fe6060f1SDimitry Andric case 'i': 14181ad6265SDimitry Andric return BasicType::Int32; 142fe6060f1SDimitry Andric break; 143fe6060f1SDimitry Andric case 'l': 14481ad6265SDimitry Andric return BasicType::Int64; 145fe6060f1SDimitry Andric break; 146fe6060f1SDimitry Andric case 'x': 14781ad6265SDimitry Andric return BasicType::Float16; 148fe6060f1SDimitry Andric break; 149fe6060f1SDimitry Andric case 'f': 15081ad6265SDimitry Andric return BasicType::Float32; 151fe6060f1SDimitry Andric break; 152fe6060f1SDimitry Andric case 'd': 15381ad6265SDimitry Andric return BasicType::Float64; 154fe6060f1SDimitry Andric break; 15581ad6265SDimitry Andric 156fe6060f1SDimitry Andric default: 15781ad6265SDimitry Andric return BasicType::Unknown; 158fe6060f1SDimitry Andric } 159fe6060f1SDimitry Andric } 160fe6060f1SDimitry Andric 16181ad6265SDimitry Andric void emitCodeGenSwitchBody(const RVVIntrinsic *RVVI, raw_ostream &OS) { 16281ad6265SDimitry Andric if (!RVVI->getIRName().empty()) 16381ad6265SDimitry Andric OS << " ID = Intrinsic::riscv_" + RVVI->getIRName() + ";\n"; 16481ad6265SDimitry Andric if (RVVI->getNF() >= 2) 16581ad6265SDimitry Andric OS << " NF = " + utostr(RVVI->getNF()) + ";\n"; 166bdd1243dSDimitry Andric 167bdd1243dSDimitry Andric OS << " PolicyAttrs = " << RVVI->getPolicyAttrsBits() << ";\n"; 168bdd1243dSDimitry Andric 16981ad6265SDimitry Andric if (RVVI->hasManualCodegen()) { 170bdd1243dSDimitry Andric OS << "IsMasked = " << (RVVI->isMasked() ? "true" : "false") << ";\n"; 17181ad6265SDimitry Andric OS << RVVI->getManualCodegen(); 172fe6060f1SDimitry Andric OS << "break;\n"; 173fe6060f1SDimitry Andric return; 174fe6060f1SDimitry Andric } 175fe6060f1SDimitry Andric 176753f127fSDimitry Andric // Cast pointer operand of vector load intrinsic. 177753f127fSDimitry Andric for (const auto &I : enumerate(RVVI->getInputTypes())) { 178753f127fSDimitry Andric if (I.value()->isPointer()) { 179753f127fSDimitry Andric assert(RVVI->getIntrinsicTypes().front() == -1 && 180753f127fSDimitry Andric "RVVI should be vector load intrinsic."); 181753f127fSDimitry Andric OS << " Ops[" << I.index() << "] = Builder.CreateBitCast(Ops["; 182753f127fSDimitry Andric OS << I.index() << "], ResultType->getPointerTo());\n"; 183753f127fSDimitry Andric } 184753f127fSDimitry Andric } 185753f127fSDimitry Andric 18681ad6265SDimitry Andric if (RVVI->isMasked()) { 18781ad6265SDimitry Andric if (RVVI->hasVL()) { 188fe6060f1SDimitry Andric OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n"; 18981ad6265SDimitry Andric if (RVVI->hasPolicyOperand()) 190349cc55cSDimitry Andric OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType()," 191bdd1243dSDimitry Andric " PolicyAttrs));\n"; 192bdd1243dSDimitry Andric if (RVVI->hasMaskedOffOperand() && RVVI->getPolicyAttrs().isTAMAPolicy()) 193bdd1243dSDimitry Andric OS << " Ops.insert(Ops.begin(), " 194bdd1243dSDimitry Andric "llvm::PoisonValue::get(ResultType));\n"; 195bdd1243dSDimitry Andric // Masked reduction cases. 196bdd1243dSDimitry Andric if (!RVVI->hasMaskedOffOperand() && RVVI->hasPassthruOperand() && 197bdd1243dSDimitry Andric RVVI->getPolicyAttrs().isTAMAPolicy()) 198bdd1243dSDimitry Andric OS << " Ops.insert(Ops.begin(), " 199bdd1243dSDimitry Andric "llvm::PoisonValue::get(ResultType));\n"; 200fe6060f1SDimitry Andric } else { 201fe6060f1SDimitry Andric OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n"; 202fe6060f1SDimitry Andric } 20381ad6265SDimitry Andric } else { 20481ad6265SDimitry Andric if (RVVI->hasPolicyOperand()) 20581ad6265SDimitry Andric OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(), " 206bdd1243dSDimitry Andric "PolicyAttrs));\n"; 207bdd1243dSDimitry Andric else if (RVVI->hasPassthruOperand() && RVVI->getPolicyAttrs().isTAPolicy()) 208bdd1243dSDimitry Andric OS << " Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));\n"; 209fe6060f1SDimitry Andric } 210fe6060f1SDimitry Andric 211fe6060f1SDimitry Andric OS << " IntrinsicTypes = {"; 212fe6060f1SDimitry Andric ListSeparator LS; 21381ad6265SDimitry Andric for (const auto &Idx : RVVI->getIntrinsicTypes()) { 214fe6060f1SDimitry Andric if (Idx == -1) 215fe6060f1SDimitry Andric OS << LS << "ResultType"; 216fe6060f1SDimitry Andric else 217fe6060f1SDimitry Andric OS << LS << "Ops[" << Idx << "]->getType()"; 218fe6060f1SDimitry Andric } 219fe6060f1SDimitry Andric 220fe6060f1SDimitry Andric // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is 221fe6060f1SDimitry Andric // always last operand. 22281ad6265SDimitry Andric if (RVVI->hasVL()) 223fe6060f1SDimitry Andric OS << ", Ops.back()->getType()"; 224fe6060f1SDimitry Andric OS << "};\n"; 225fe6060f1SDimitry Andric OS << " break;\n"; 226fe6060f1SDimitry Andric } 227fe6060f1SDimitry Andric 228972a253aSDimitry Andric //===----------------------------------------------------------------------===// 229972a253aSDimitry Andric // SemaSignatureTable implementation 230972a253aSDimitry Andric //===----------------------------------------------------------------------===// 231972a253aSDimitry Andric void SemaSignatureTable::init(ArrayRef<SemaRecord> SemaRecords) { 232972a253aSDimitry Andric // Sort signature entries by length, let longer signature insert first, to 233972a253aSDimitry Andric // make it more possible to reuse table entries, that can reduce ~10% table 234972a253aSDimitry Andric // size. 235972a253aSDimitry Andric struct Compare { 236972a253aSDimitry Andric bool operator()(const SmallVector<PrototypeDescriptor> &A, 237972a253aSDimitry Andric const SmallVector<PrototypeDescriptor> &B) const { 238972a253aSDimitry Andric if (A.size() != B.size()) 239972a253aSDimitry Andric return A.size() > B.size(); 240972a253aSDimitry Andric 241972a253aSDimitry Andric size_t Len = A.size(); 242972a253aSDimitry Andric for (size_t i = 0; i < Len; ++i) { 243972a253aSDimitry Andric if (A[i] != B[i]) 244972a253aSDimitry Andric return A[i] < B[i]; 245fe6060f1SDimitry Andric } 246fe6060f1SDimitry Andric 247972a253aSDimitry Andric return false; 248fe6060f1SDimitry Andric } 249972a253aSDimitry Andric }; 250972a253aSDimitry Andric 251972a253aSDimitry Andric std::set<SmallVector<PrototypeDescriptor>, Compare> Signatures; 252972a253aSDimitry Andric auto InsertToSignatureSet = 253972a253aSDimitry Andric [&](const SmallVector<PrototypeDescriptor> &Signature) { 254972a253aSDimitry Andric if (Signature.empty()) 255972a253aSDimitry Andric return; 256972a253aSDimitry Andric 257972a253aSDimitry Andric Signatures.insert(Signature); 258972a253aSDimitry Andric }; 259972a253aSDimitry Andric 260972a253aSDimitry Andric assert(!SemaRecords.empty()); 261972a253aSDimitry Andric 262972a253aSDimitry Andric llvm::for_each(SemaRecords, [&](const SemaRecord &SR) { 263972a253aSDimitry Andric InsertToSignatureSet(SR.Prototype); 264972a253aSDimitry Andric InsertToSignatureSet(SR.Suffix); 265972a253aSDimitry Andric InsertToSignatureSet(SR.OverloadedSuffix); 266972a253aSDimitry Andric }); 267972a253aSDimitry Andric 268972a253aSDimitry Andric llvm::for_each(Signatures, [this](auto &Sig) { insert(Sig); }); 269972a253aSDimitry Andric } 270972a253aSDimitry Andric 271972a253aSDimitry Andric void SemaSignatureTable::insert(ArrayRef<PrototypeDescriptor> Signature) { 272972a253aSDimitry Andric if (getIndex(Signature) != INVALID_INDEX) 273972a253aSDimitry Andric return; 274972a253aSDimitry Andric 275972a253aSDimitry Andric // Insert Signature into SignatureTable if not found in the table. 276972a253aSDimitry Andric SignatureTable.insert(SignatureTable.begin(), Signature.begin(), 277972a253aSDimitry Andric Signature.end()); 278972a253aSDimitry Andric } 279972a253aSDimitry Andric 280972a253aSDimitry Andric unsigned SemaSignatureTable::getIndex(ArrayRef<PrototypeDescriptor> Signature) { 281972a253aSDimitry Andric // Empty signature could be point into any index since there is length 282972a253aSDimitry Andric // field when we use, so just always point it to 0. 283972a253aSDimitry Andric if (Signature.empty()) 284972a253aSDimitry Andric return 0; 285972a253aSDimitry Andric 286972a253aSDimitry Andric // Checking Signature already in table or not. 287972a253aSDimitry Andric if (Signature.size() < SignatureTable.size()) { 288972a253aSDimitry Andric size_t Bound = SignatureTable.size() - Signature.size() + 1; 289972a253aSDimitry Andric for (size_t Index = 0; Index < Bound; ++Index) { 290972a253aSDimitry Andric if (equal(Signature.begin(), Signature.end(), 291972a253aSDimitry Andric SignatureTable.begin() + Index)) 292972a253aSDimitry Andric return Index; 293972a253aSDimitry Andric } 294972a253aSDimitry Andric } 295972a253aSDimitry Andric 296972a253aSDimitry Andric return INVALID_INDEX; 297972a253aSDimitry Andric } 298972a253aSDimitry Andric 299972a253aSDimitry Andric void SemaSignatureTable::print(raw_ostream &OS) { 300972a253aSDimitry Andric for (const auto &Sig : SignatureTable) 301972a253aSDimitry Andric OS << "PrototypeDescriptor(" << static_cast<int>(Sig.PT) << ", " 302972a253aSDimitry Andric << static_cast<int>(Sig.VTM) << ", " << static_cast<int>(Sig.TM) 303972a253aSDimitry Andric << "),\n"; 304fe6060f1SDimitry Andric } 305fe6060f1SDimitry Andric 306fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 307fe6060f1SDimitry Andric // RVVEmitter implementation 308fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 309fe6060f1SDimitry Andric void RVVEmitter::createHeader(raw_ostream &OS) { 310fe6060f1SDimitry Andric 311fe6060f1SDimitry Andric OS << "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics " 312fe6060f1SDimitry Andric "-------------------===\n" 313fe6060f1SDimitry Andric " *\n" 314fe6060f1SDimitry Andric " *\n" 315fe6060f1SDimitry Andric " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " 316fe6060f1SDimitry Andric "Exceptions.\n" 317fe6060f1SDimitry Andric " * See https://llvm.org/LICENSE.txt for license information.\n" 318fe6060f1SDimitry Andric " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 319fe6060f1SDimitry Andric " *\n" 320fe6060f1SDimitry Andric " *===-----------------------------------------------------------------" 321fe6060f1SDimitry Andric "------===\n" 322fe6060f1SDimitry Andric " */\n\n"; 323fe6060f1SDimitry Andric 324fe6060f1SDimitry Andric OS << "#ifndef __RISCV_VECTOR_H\n"; 325fe6060f1SDimitry Andric OS << "#define __RISCV_VECTOR_H\n\n"; 326fe6060f1SDimitry Andric 327fe6060f1SDimitry Andric OS << "#include <stdint.h>\n"; 328fe6060f1SDimitry Andric OS << "#include <stddef.h>\n\n"; 329fe6060f1SDimitry Andric 330fe6060f1SDimitry Andric OS << "#ifndef __riscv_vector\n"; 331fe6060f1SDimitry Andric OS << "#error \"Vector intrinsics require the vector extension.\"\n"; 332fe6060f1SDimitry Andric OS << "#endif\n\n"; 333fe6060f1SDimitry Andric 334fe6060f1SDimitry Andric OS << "#ifdef __cplusplus\n"; 335fe6060f1SDimitry Andric OS << "extern \"C\" {\n"; 336fe6060f1SDimitry Andric OS << "#endif\n\n"; 337fe6060f1SDimitry Andric 338972a253aSDimitry Andric OS << "#pragma clang riscv intrinsic vector\n\n"; 339349cc55cSDimitry Andric 340972a253aSDimitry Andric printHeaderCode(OS); 341fe6060f1SDimitry Andric 342fe6060f1SDimitry Andric auto printType = [&](auto T) { 343fe6060f1SDimitry Andric OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr() 344fe6060f1SDimitry Andric << ";\n"; 345fe6060f1SDimitry Andric }; 346fe6060f1SDimitry Andric 347fe6060f1SDimitry Andric constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3}; 348fe6060f1SDimitry Andric // Print RVV boolean types. 349fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 350bdd1243dSDimitry Andric auto T = TypeCache.computeType(BasicType::Int8, Log2LMUL, 35181ad6265SDimitry Andric PrototypeDescriptor::Mask); 35281ad6265SDimitry Andric if (T) 353bdd1243dSDimitry Andric printType(*T); 354fe6060f1SDimitry Andric } 355fe6060f1SDimitry Andric // Print RVV int/float types. 356fe6060f1SDimitry Andric for (char I : StringRef("csil")) { 35781ad6265SDimitry Andric BasicType BT = ParseBasicType(I); 358fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 359bdd1243dSDimitry Andric auto T = TypeCache.computeType(BT, Log2LMUL, PrototypeDescriptor::Vector); 36081ad6265SDimitry Andric if (T) { 361bdd1243dSDimitry Andric printType(*T); 362bdd1243dSDimitry Andric auto UT = TypeCache.computeType( 36381ad6265SDimitry Andric BT, Log2LMUL, 36481ad6265SDimitry Andric PrototypeDescriptor(BaseTypeModifier::Vector, 36581ad6265SDimitry Andric VectorTypeModifier::NoModifier, 36681ad6265SDimitry Andric TypeModifier::UnsignedInteger)); 367bdd1243dSDimitry Andric printType(*UT); 368fe6060f1SDimitry Andric } 369fe6060f1SDimitry Andric } 370fe6060f1SDimitry Andric } 37181ad6265SDimitry Andric OS << "#if defined(__riscv_zvfh)\n"; 372fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 373bdd1243dSDimitry Andric auto T = TypeCache.computeType(BasicType::Float16, Log2LMUL, 37481ad6265SDimitry Andric PrototypeDescriptor::Vector); 37581ad6265SDimitry Andric if (T) 376bdd1243dSDimitry Andric printType(*T); 377fe6060f1SDimitry Andric } 378fe6060f1SDimitry Andric OS << "#endif\n"; 379fe6060f1SDimitry Andric 380972a253aSDimitry Andric OS << "#if (__riscv_v_elen_fp >= 32)\n"; 381fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 382bdd1243dSDimitry Andric auto T = TypeCache.computeType(BasicType::Float32, Log2LMUL, 38381ad6265SDimitry Andric PrototypeDescriptor::Vector); 38481ad6265SDimitry Andric if (T) 385bdd1243dSDimitry Andric printType(*T); 386fe6060f1SDimitry Andric } 387fe6060f1SDimitry Andric OS << "#endif\n"; 388fe6060f1SDimitry Andric 389972a253aSDimitry Andric OS << "#if (__riscv_v_elen_fp >= 64)\n"; 390fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 391bdd1243dSDimitry Andric auto T = TypeCache.computeType(BasicType::Float64, Log2LMUL, 39281ad6265SDimitry Andric PrototypeDescriptor::Vector); 39381ad6265SDimitry Andric if (T) 394bdd1243dSDimitry Andric printType(*T); 395fe6060f1SDimitry Andric } 396fe6060f1SDimitry Andric OS << "#endif\n\n"; 397fe6060f1SDimitry Andric 398fe6060f1SDimitry Andric OS << "#define __riscv_v_intrinsic_overloading 1\n"; 399fe6060f1SDimitry Andric 400fe6060f1SDimitry Andric OS << "\n#ifdef __cplusplus\n"; 401fe6060f1SDimitry Andric OS << "}\n"; 402349cc55cSDimitry Andric OS << "#endif // __cplusplus\n"; 403fe6060f1SDimitry Andric OS << "#endif // __RISCV_VECTOR_H\n"; 404fe6060f1SDimitry Andric } 405fe6060f1SDimitry Andric 406fe6060f1SDimitry Andric void RVVEmitter::createBuiltins(raw_ostream &OS) { 407fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 408fe6060f1SDimitry Andric createRVVIntrinsics(Defs); 409fe6060f1SDimitry Andric 410349cc55cSDimitry Andric // Map to keep track of which builtin names have already been emitted. 411349cc55cSDimitry Andric StringMap<RVVIntrinsic *> BuiltinMap; 412349cc55cSDimitry Andric 413fe6060f1SDimitry Andric OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n"; 414fe6060f1SDimitry Andric OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, " 41581ad6265SDimitry Andric "ATTRS, \"zve32x\")\n"; 416fe6060f1SDimitry Andric OS << "#endif\n"; 417fe6060f1SDimitry Andric for (auto &Def : Defs) { 418349cc55cSDimitry Andric auto P = 419349cc55cSDimitry Andric BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); 420349cc55cSDimitry Andric if (!P.second) { 42181ad6265SDimitry Andric // Verf that this would have produced the same builtin definition. 42281ad6265SDimitry Andric if (P.first->second->hasBuiltinAlias() != Def->hasBuiltinAlias()) 423349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different hasAutoDef"); 42481ad6265SDimitry Andric else if (!Def->hasBuiltinAlias() && 42581ad6265SDimitry Andric P.first->second->getBuiltinTypeStr() != Def->getBuiltinTypeStr()) 426349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different type string"); 427349cc55cSDimitry Andric continue; 428349cc55cSDimitry Andric } 429349cc55cSDimitry Andric OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getBuiltinName() << ",\""; 43081ad6265SDimitry Andric if (!Def->hasBuiltinAlias()) 431349cc55cSDimitry Andric OS << Def->getBuiltinTypeStr(); 432349cc55cSDimitry Andric OS << "\", \"n\")\n"; 433fe6060f1SDimitry Andric } 434fe6060f1SDimitry Andric OS << "#undef RISCVV_BUILTIN\n"; 435fe6060f1SDimitry Andric } 436fe6060f1SDimitry Andric 437fe6060f1SDimitry Andric void RVVEmitter::createCodeGen(raw_ostream &OS) { 438fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 439fe6060f1SDimitry Andric createRVVIntrinsics(Defs); 440fe6060f1SDimitry Andric // IR name could be empty, use the stable sort preserves the relative order. 441349cc55cSDimitry Andric llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A, 442fe6060f1SDimitry Andric const std::unique_ptr<RVVIntrinsic> &B) { 443bdd1243dSDimitry Andric if (A->getIRName() == B->getIRName()) 444bdd1243dSDimitry Andric return (A->getPolicyAttrs() < B->getPolicyAttrs()); 445bdd1243dSDimitry Andric return (A->getIRName() < B->getIRName()); 446fe6060f1SDimitry Andric }); 447349cc55cSDimitry Andric 448349cc55cSDimitry Andric // Map to keep track of which builtin names have already been emitted. 449349cc55cSDimitry Andric StringMap<RVVIntrinsic *> BuiltinMap; 450349cc55cSDimitry Andric 451bdd1243dSDimitry Andric // Print switch body when the ir name, ManualCodegen or policy changes from 452bdd1243dSDimitry Andric // previous iteration. 453fe6060f1SDimitry Andric RVVIntrinsic *PrevDef = Defs.begin()->get(); 454fe6060f1SDimitry Andric for (auto &Def : Defs) { 455fe6060f1SDimitry Andric StringRef CurIRName = Def->getIRName(); 456fe6060f1SDimitry Andric if (CurIRName != PrevDef->getIRName() || 457bdd1243dSDimitry Andric (Def->getManualCodegen() != PrevDef->getManualCodegen()) || 458bdd1243dSDimitry Andric (Def->getPolicyAttrs() != PrevDef->getPolicyAttrs())) { 45981ad6265SDimitry Andric emitCodeGenSwitchBody(PrevDef, OS); 460fe6060f1SDimitry Andric } 461fe6060f1SDimitry Andric PrevDef = Def.get(); 462349cc55cSDimitry Andric 463349cc55cSDimitry Andric auto P = 464349cc55cSDimitry Andric BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); 465349cc55cSDimitry Andric if (P.second) { 466349cc55cSDimitry Andric OS << "case RISCVVector::BI__builtin_rvv_" << Def->getBuiltinName() 467349cc55cSDimitry Andric << ":\n"; 468349cc55cSDimitry Andric continue; 469349cc55cSDimitry Andric } 470349cc55cSDimitry Andric 471349cc55cSDimitry Andric if (P.first->second->getIRName() != Def->getIRName()) 472349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different IRName"); 473349cc55cSDimitry Andric else if (P.first->second->getManualCodegen() != Def->getManualCodegen()) 474349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different ManualCodegen"); 475349cc55cSDimitry Andric else if (P.first->second->getNF() != Def->getNF()) 476349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different NF"); 47781ad6265SDimitry Andric else if (P.first->second->isMasked() != Def->isMasked()) 47881ad6265SDimitry Andric PrintFatalError("Builtin with same name has different isMasked"); 479349cc55cSDimitry Andric else if (P.first->second->hasVL() != Def->hasVL()) 48081ad6265SDimitry Andric PrintFatalError("Builtin with same name has different hasVL"); 48181ad6265SDimitry Andric else if (P.first->second->getPolicyScheme() != Def->getPolicyScheme()) 48281ad6265SDimitry Andric PrintFatalError("Builtin with same name has different getPolicyScheme"); 483349cc55cSDimitry Andric else if (P.first->second->getIntrinsicTypes() != Def->getIntrinsicTypes()) 484349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different IntrinsicTypes"); 485fe6060f1SDimitry Andric } 48681ad6265SDimitry Andric emitCodeGenSwitchBody(Defs.back().get(), OS); 487fe6060f1SDimitry Andric OS << "\n"; 488fe6060f1SDimitry Andric } 489fe6060f1SDimitry Andric 490fe6060f1SDimitry Andric void RVVEmitter::createRVVIntrinsics( 491972a253aSDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> &Out, 492972a253aSDimitry Andric std::vector<SemaRecord> *SemaRecords) { 493fe6060f1SDimitry Andric std::vector<Record *> RV = Records.getAllDerivedDefinitions("RVVBuiltin"); 494fe6060f1SDimitry Andric for (auto *R : RV) { 495fe6060f1SDimitry Andric StringRef Name = R->getValueAsString("Name"); 496fe6060f1SDimitry Andric StringRef SuffixProto = R->getValueAsString("Suffix"); 49781ad6265SDimitry Andric StringRef OverloadedName = R->getValueAsString("OverloadedName"); 49881ad6265SDimitry Andric StringRef OverloadedSuffixProto = R->getValueAsString("OverloadedSuffix"); 499fe6060f1SDimitry Andric StringRef Prototypes = R->getValueAsString("Prototype"); 500fe6060f1SDimitry Andric StringRef TypeRange = R->getValueAsString("TypeRange"); 50181ad6265SDimitry Andric bool HasMasked = R->getValueAsBit("HasMasked"); 502fe6060f1SDimitry Andric bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand"); 503fe6060f1SDimitry Andric bool HasVL = R->getValueAsBit("HasVL"); 504972a253aSDimitry Andric Record *MPSRecord = R->getValueAsDef("MaskedPolicyScheme"); 505972a253aSDimitry Andric auto MaskedPolicyScheme = 506972a253aSDimitry Andric static_cast<PolicyScheme>(MPSRecord->getValueAsInt("Value")); 507972a253aSDimitry Andric Record *UMPSRecord = R->getValueAsDef("UnMaskedPolicyScheme"); 508972a253aSDimitry Andric auto UnMaskedPolicyScheme = 509972a253aSDimitry Andric static_cast<PolicyScheme>(UMPSRecord->getValueAsInt("Value")); 510fe6060f1SDimitry Andric std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL"); 511bdd1243dSDimitry Andric bool HasTailPolicy = R->getValueAsBit("HasTailPolicy"); 512bdd1243dSDimitry Andric bool HasMaskPolicy = R->getValueAsBit("HasMaskPolicy"); 513bdd1243dSDimitry Andric bool SupportOverloading = R->getValueAsBit("SupportOverloading"); 51481ad6265SDimitry Andric bool HasBuiltinAlias = R->getValueAsBit("HasBuiltinAlias"); 515fe6060f1SDimitry Andric StringRef ManualCodegen = R->getValueAsString("ManualCodegen"); 516fe6060f1SDimitry Andric std::vector<int64_t> IntrinsicTypes = 517fe6060f1SDimitry Andric R->getValueAsListOfInts("IntrinsicTypes"); 51804eeddc0SDimitry Andric std::vector<StringRef> RequiredFeatures = 51904eeddc0SDimitry Andric R->getValueAsListOfStrings("RequiredFeatures"); 520fe6060f1SDimitry Andric StringRef IRName = R->getValueAsString("IRName"); 52181ad6265SDimitry Andric StringRef MaskedIRName = R->getValueAsString("MaskedIRName"); 522fe6060f1SDimitry Andric unsigned NF = R->getValueAsInt("NF"); 523fe6060f1SDimitry Andric 524*1ac55f4cSDimitry Andric const Policy DefaultPolicy; 525bdd1243dSDimitry Andric SmallVector<Policy> SupportedUnMaskedPolicies = 526*1ac55f4cSDimitry Andric RVVIntrinsic::getSupportedUnMaskedPolicies(); 527bdd1243dSDimitry Andric SmallVector<Policy> SupportedMaskedPolicies = 528bdd1243dSDimitry Andric RVVIntrinsic::getSupportedMaskedPolicies(HasTailPolicy, HasMaskPolicy); 529bdd1243dSDimitry Andric 530fe6060f1SDimitry Andric // Parse prototype and create a list of primitive type with transformers 53181ad6265SDimitry Andric // (operand) in Prototype. Prototype[0] is output operand. 532972a253aSDimitry Andric SmallVector<PrototypeDescriptor> BasicPrototype = 533972a253aSDimitry Andric parsePrototypes(Prototypes); 53481ad6265SDimitry Andric 53581ad6265SDimitry Andric SmallVector<PrototypeDescriptor> SuffixDesc = parsePrototypes(SuffixProto); 53681ad6265SDimitry Andric SmallVector<PrototypeDescriptor> OverloadedSuffixDesc = 53781ad6265SDimitry Andric parsePrototypes(OverloadedSuffixProto); 538fe6060f1SDimitry Andric 539fe6060f1SDimitry Andric // Compute Builtin types 540972a253aSDimitry Andric auto Prototype = RVVIntrinsic::computeBuiltinTypes( 541bdd1243dSDimitry Andric BasicPrototype, /*IsMasked=*/false, 542bdd1243dSDimitry Andric /*HasMaskedOffOperand=*/false, HasVL, NF, UnMaskedPolicyScheme, 543bdd1243dSDimitry Andric DefaultPolicy); 544972a253aSDimitry Andric auto MaskedPrototype = RVVIntrinsic::computeBuiltinTypes( 545bdd1243dSDimitry Andric BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, NF, 546bdd1243dSDimitry Andric MaskedPolicyScheme, DefaultPolicy); 547fe6060f1SDimitry Andric 548fe6060f1SDimitry Andric // Create Intrinsics for each type and LMUL. 549fe6060f1SDimitry Andric for (char I : TypeRange) { 550fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULList) { 55181ad6265SDimitry Andric BasicType BT = ParseBasicType(I); 552bdd1243dSDimitry Andric std::optional<RVVTypes> Types = 553bdd1243dSDimitry Andric TypeCache.computeTypes(BT, Log2LMUL, NF, Prototype); 554fe6060f1SDimitry Andric // Ignored to create new intrinsic if there are any illegal types. 55581ad6265SDimitry Andric if (!Types) 556fe6060f1SDimitry Andric continue; 557fe6060f1SDimitry Andric 558bdd1243dSDimitry Andric auto SuffixStr = 559bdd1243dSDimitry Andric RVVIntrinsic::getSuffixStr(TypeCache, BT, Log2LMUL, SuffixDesc); 560bdd1243dSDimitry Andric auto OverloadedSuffixStr = RVVIntrinsic::getSuffixStr( 561bdd1243dSDimitry Andric TypeCache, BT, Log2LMUL, OverloadedSuffixDesc); 56281ad6265SDimitry Andric // Create a unmasked intrinsic 563fe6060f1SDimitry Andric Out.push_back(std::make_unique<RVVIntrinsic>( 56481ad6265SDimitry Andric Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName, 56581ad6265SDimitry Andric /*IsMasked=*/false, /*HasMaskedOffOperand=*/false, HasVL, 566bdd1243dSDimitry Andric UnMaskedPolicyScheme, SupportOverloading, HasBuiltinAlias, 567bdd1243dSDimitry Andric ManualCodegen, *Types, IntrinsicTypes, RequiredFeatures, NF, 568bdd1243dSDimitry Andric DefaultPolicy)); 569bdd1243dSDimitry Andric if (UnMaskedPolicyScheme != PolicyScheme::SchemeNone) 570bdd1243dSDimitry Andric for (auto P : SupportedUnMaskedPolicies) { 571bdd1243dSDimitry Andric SmallVector<PrototypeDescriptor> PolicyPrototype = 572bdd1243dSDimitry Andric RVVIntrinsic::computeBuiltinTypes( 573bdd1243dSDimitry Andric BasicPrototype, /*IsMasked=*/false, 574bdd1243dSDimitry Andric /*HasMaskedOffOperand=*/false, HasVL, NF, 575bdd1243dSDimitry Andric UnMaskedPolicyScheme, P); 576bdd1243dSDimitry Andric std::optional<RVVTypes> PolicyTypes = 577bdd1243dSDimitry Andric TypeCache.computeTypes(BT, Log2LMUL, NF, PolicyPrototype); 578bdd1243dSDimitry Andric Out.push_back(std::make_unique<RVVIntrinsic>( 579bdd1243dSDimitry Andric Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName, 580bdd1243dSDimitry Andric /*IsMask=*/false, /*HasMaskedOffOperand=*/false, HasVL, 581bdd1243dSDimitry Andric UnMaskedPolicyScheme, SupportOverloading, HasBuiltinAlias, 582bdd1243dSDimitry Andric ManualCodegen, *PolicyTypes, IntrinsicTypes, RequiredFeatures, 583bdd1243dSDimitry Andric NF, P)); 584bdd1243dSDimitry Andric } 585bdd1243dSDimitry Andric if (!HasMasked) 586bdd1243dSDimitry Andric continue; 58781ad6265SDimitry Andric // Create a masked intrinsic 588bdd1243dSDimitry Andric std::optional<RVVTypes> MaskTypes = 589bdd1243dSDimitry Andric TypeCache.computeTypes(BT, Log2LMUL, NF, MaskedPrototype); 590bdd1243dSDimitry Andric Out.push_back(std::make_unique<RVVIntrinsic>( 591bdd1243dSDimitry Andric Name, SuffixStr, OverloadedName, OverloadedSuffixStr, MaskedIRName, 592bdd1243dSDimitry Andric /*IsMasked=*/true, HasMaskedOffOperand, HasVL, MaskedPolicyScheme, 593bdd1243dSDimitry Andric SupportOverloading, HasBuiltinAlias, ManualCodegen, *MaskTypes, 594bdd1243dSDimitry Andric IntrinsicTypes, RequiredFeatures, NF, DefaultPolicy)); 595bdd1243dSDimitry Andric if (MaskedPolicyScheme == PolicyScheme::SchemeNone) 596bdd1243dSDimitry Andric continue; 597bdd1243dSDimitry Andric for (auto P : SupportedMaskedPolicies) { 598bdd1243dSDimitry Andric SmallVector<PrototypeDescriptor> PolicyPrototype = 599bdd1243dSDimitry Andric RVVIntrinsic::computeBuiltinTypes( 600bdd1243dSDimitry Andric BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, 601bdd1243dSDimitry Andric NF, MaskedPolicyScheme, P); 602bdd1243dSDimitry Andric std::optional<RVVTypes> PolicyTypes = 603bdd1243dSDimitry Andric TypeCache.computeTypes(BT, Log2LMUL, NF, PolicyPrototype); 604fe6060f1SDimitry Andric Out.push_back(std::make_unique<RVVIntrinsic>( 60581ad6265SDimitry Andric Name, SuffixStr, OverloadedName, OverloadedSuffixStr, 606bdd1243dSDimitry Andric MaskedIRName, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, 607bdd1243dSDimitry Andric MaskedPolicyScheme, SupportOverloading, HasBuiltinAlias, 608bdd1243dSDimitry Andric ManualCodegen, *PolicyTypes, IntrinsicTypes, RequiredFeatures, NF, 609bdd1243dSDimitry Andric P)); 610fe6060f1SDimitry Andric } 611bdd1243dSDimitry Andric } // End for Log2LMULList 612bdd1243dSDimitry Andric } // End for TypeRange 613972a253aSDimitry Andric 614972a253aSDimitry Andric // We don't emit vsetvli and vsetvlimax for SemaRecord. 615972a253aSDimitry Andric // They are written in riscv_vector.td and will emit those marco define in 616972a253aSDimitry Andric // riscv_vector.h 617972a253aSDimitry Andric if (Name == "vsetvli" || Name == "vsetvlimax") 618972a253aSDimitry Andric continue; 619972a253aSDimitry Andric 620972a253aSDimitry Andric if (!SemaRecords) 621972a253aSDimitry Andric continue; 622972a253aSDimitry Andric 623972a253aSDimitry Andric // Create SemaRecord 624972a253aSDimitry Andric SemaRecord SR; 625972a253aSDimitry Andric SR.Name = Name.str(); 626972a253aSDimitry Andric SR.OverloadedName = OverloadedName.str(); 627972a253aSDimitry Andric BasicType TypeRangeMask = BasicType::Unknown; 628972a253aSDimitry Andric for (char I : TypeRange) 629972a253aSDimitry Andric TypeRangeMask |= ParseBasicType(I); 630972a253aSDimitry Andric 631972a253aSDimitry Andric SR.TypeRangeMask = static_cast<unsigned>(TypeRangeMask); 632972a253aSDimitry Andric 633972a253aSDimitry Andric unsigned Log2LMULMask = 0; 634972a253aSDimitry Andric for (int Log2LMUL : Log2LMULList) 635972a253aSDimitry Andric Log2LMULMask |= 1 << (Log2LMUL + 3); 636972a253aSDimitry Andric 637972a253aSDimitry Andric SR.Log2LMULMask = Log2LMULMask; 638972a253aSDimitry Andric 639972a253aSDimitry Andric SR.RequiredExtensions = 0; 640972a253aSDimitry Andric for (auto RequiredFeature : RequiredFeatures) { 641972a253aSDimitry Andric RVVRequire RequireExt = StringSwitch<RVVRequire>(RequiredFeature) 642972a253aSDimitry Andric .Case("RV64", RVV_REQ_RV64) 643972a253aSDimitry Andric .Case("FullMultiply", RVV_REQ_FullMultiply) 644972a253aSDimitry Andric .Default(RVV_REQ_None); 645972a253aSDimitry Andric assert(RequireExt != RVV_REQ_None && "Unrecognized required feature?"); 646972a253aSDimitry Andric SR.RequiredExtensions |= RequireExt; 647972a253aSDimitry Andric } 648972a253aSDimitry Andric 649972a253aSDimitry Andric SR.NF = NF; 650972a253aSDimitry Andric SR.HasMasked = HasMasked; 651972a253aSDimitry Andric SR.HasVL = HasVL; 652972a253aSDimitry Andric SR.HasMaskedOffOperand = HasMaskedOffOperand; 653bdd1243dSDimitry Andric SR.HasTailPolicy = HasTailPolicy; 654bdd1243dSDimitry Andric SR.HasMaskPolicy = HasMaskPolicy; 655bdd1243dSDimitry Andric SR.UnMaskedPolicyScheme = static_cast<uint8_t>(UnMaskedPolicyScheme); 656bdd1243dSDimitry Andric SR.MaskedPolicyScheme = static_cast<uint8_t>(MaskedPolicyScheme); 657972a253aSDimitry Andric SR.Prototype = std::move(BasicPrototype); 658972a253aSDimitry Andric SR.Suffix = parsePrototypes(SuffixProto); 659972a253aSDimitry Andric SR.OverloadedSuffix = parsePrototypes(OverloadedSuffixProto); 660972a253aSDimitry Andric 661972a253aSDimitry Andric SemaRecords->push_back(SR); 662fe6060f1SDimitry Andric } 663fe6060f1SDimitry Andric } 664fe6060f1SDimitry Andric 66581ad6265SDimitry Andric void RVVEmitter::printHeaderCode(raw_ostream &OS) { 666349cc55cSDimitry Andric std::vector<Record *> RVVHeaders = 667349cc55cSDimitry Andric Records.getAllDerivedDefinitions("RVVHeader"); 668349cc55cSDimitry Andric for (auto *R : RVVHeaders) { 669349cc55cSDimitry Andric StringRef HeaderCodeStr = R->getValueAsString("HeaderCode"); 670349cc55cSDimitry Andric OS << HeaderCodeStr.str(); 671349cc55cSDimitry Andric } 672349cc55cSDimitry Andric } 673349cc55cSDimitry Andric 674972a253aSDimitry Andric void RVVEmitter::createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out, 675972a253aSDimitry Andric SemaSignatureTable &SST, 676972a253aSDimitry Andric ArrayRef<SemaRecord> SemaRecords) { 677972a253aSDimitry Andric SST.init(SemaRecords); 678972a253aSDimitry Andric 679972a253aSDimitry Andric for (const auto &SR : SemaRecords) { 680972a253aSDimitry Andric Out.emplace_back(RVVIntrinsicRecord()); 681972a253aSDimitry Andric RVVIntrinsicRecord &R = Out.back(); 682972a253aSDimitry Andric R.Name = SR.Name.c_str(); 683972a253aSDimitry Andric R.OverloadedName = SR.OverloadedName.c_str(); 684972a253aSDimitry Andric R.PrototypeIndex = SST.getIndex(SR.Prototype); 685972a253aSDimitry Andric R.SuffixIndex = SST.getIndex(SR.Suffix); 686972a253aSDimitry Andric R.OverloadedSuffixIndex = SST.getIndex(SR.OverloadedSuffix); 687972a253aSDimitry Andric R.PrototypeLength = SR.Prototype.size(); 688972a253aSDimitry Andric R.SuffixLength = SR.Suffix.size(); 689972a253aSDimitry Andric R.OverloadedSuffixSize = SR.OverloadedSuffix.size(); 690972a253aSDimitry Andric R.RequiredExtensions = SR.RequiredExtensions; 691972a253aSDimitry Andric R.TypeRangeMask = SR.TypeRangeMask; 692972a253aSDimitry Andric R.Log2LMULMask = SR.Log2LMULMask; 693972a253aSDimitry Andric R.NF = SR.NF; 694972a253aSDimitry Andric R.HasMasked = SR.HasMasked; 695972a253aSDimitry Andric R.HasVL = SR.HasVL; 696972a253aSDimitry Andric R.HasMaskedOffOperand = SR.HasMaskedOffOperand; 697bdd1243dSDimitry Andric R.HasTailPolicy = SR.HasTailPolicy; 698bdd1243dSDimitry Andric R.HasMaskPolicy = SR.HasMaskPolicy; 699bdd1243dSDimitry Andric R.UnMaskedPolicyScheme = SR.UnMaskedPolicyScheme; 700bdd1243dSDimitry Andric R.MaskedPolicyScheme = SR.MaskedPolicyScheme; 701972a253aSDimitry Andric 702972a253aSDimitry Andric assert(R.PrototypeIndex != 703972a253aSDimitry Andric static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 704972a253aSDimitry Andric assert(R.SuffixIndex != 705972a253aSDimitry Andric static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 706972a253aSDimitry Andric assert(R.OverloadedSuffixIndex != 707972a253aSDimitry Andric static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 708fe6060f1SDimitry Andric } 709fe6060f1SDimitry Andric } 710fe6060f1SDimitry Andric 711972a253aSDimitry Andric void RVVEmitter::createSema(raw_ostream &OS) { 712972a253aSDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 713972a253aSDimitry Andric std::vector<RVVIntrinsicRecord> RVVIntrinsicRecords; 714972a253aSDimitry Andric SemaSignatureTable SST; 715972a253aSDimitry Andric std::vector<SemaRecord> SemaRecords; 716972a253aSDimitry Andric 717972a253aSDimitry Andric createRVVIntrinsics(Defs, &SemaRecords); 718972a253aSDimitry Andric 719972a253aSDimitry Andric createRVVIntrinsicRecords(RVVIntrinsicRecords, SST, SemaRecords); 720972a253aSDimitry Andric 721972a253aSDimitry Andric // Emit signature table for SemaRISCVVectorLookup.cpp. 722972a253aSDimitry Andric OS << "#ifdef DECL_SIGNATURE_TABLE\n"; 723972a253aSDimitry Andric SST.print(OS); 724972a253aSDimitry Andric OS << "#endif\n"; 725972a253aSDimitry Andric 726972a253aSDimitry Andric // Emit RVVIntrinsicRecords for SemaRISCVVectorLookup.cpp. 727972a253aSDimitry Andric OS << "#ifdef DECL_INTRINSIC_RECORDS\n"; 728972a253aSDimitry Andric for (const RVVIntrinsicRecord &Record : RVVIntrinsicRecords) 729972a253aSDimitry Andric OS << Record; 730972a253aSDimitry Andric OS << "#endif\n"; 731fe6060f1SDimitry Andric } 732fe6060f1SDimitry Andric 733fe6060f1SDimitry Andric namespace clang { 734fe6060f1SDimitry Andric void EmitRVVHeader(RecordKeeper &Records, raw_ostream &OS) { 735fe6060f1SDimitry Andric RVVEmitter(Records).createHeader(OS); 736fe6060f1SDimitry Andric } 737fe6060f1SDimitry Andric 738fe6060f1SDimitry Andric void EmitRVVBuiltins(RecordKeeper &Records, raw_ostream &OS) { 739fe6060f1SDimitry Andric RVVEmitter(Records).createBuiltins(OS); 740fe6060f1SDimitry Andric } 741fe6060f1SDimitry Andric 742fe6060f1SDimitry Andric void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 743fe6060f1SDimitry Andric RVVEmitter(Records).createCodeGen(OS); 744fe6060f1SDimitry Andric } 745fe6060f1SDimitry Andric 746972a253aSDimitry Andric void EmitRVVBuiltinSema(RecordKeeper &Records, raw_ostream &OS) { 747972a253aSDimitry Andric RVVEmitter(Records).createSema(OS); 748972a253aSDimitry Andric } 749972a253aSDimitry Andric 750fe6060f1SDimitry Andric } // End namespace clang 751