1 //===- RISCVVEmitter.cpp - Generate riscv_vector.h for use with clang -----===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This tablegen backend is responsible for emitting riscv_vector.h which 10 // includes a declaration and definition of each intrinsic functions specified 11 // in https://github.com/riscv/rvv-intrinsic-doc. 12 // 13 // See also the documentation in include/clang/Basic/riscv_vector.td. 14 // 15 //===----------------------------------------------------------------------===// 16 17 #include "clang/Support/RISCVVIntrinsicUtils.h" 18 #include "llvm/ADT/ArrayRef.h" 19 #include "llvm/ADT/SmallSet.h" 20 #include "llvm/ADT/StringExtras.h" 21 #include "llvm/ADT/StringMap.h" 22 #include "llvm/ADT/StringSet.h" 23 #include "llvm/ADT/StringSwitch.h" 24 #include "llvm/ADT/Twine.h" 25 #include "llvm/TableGen/Error.h" 26 #include "llvm/TableGen/Record.h" 27 #include <numeric> 28 29 using namespace llvm; 30 using namespace clang::RISCV; 31 32 namespace { 33 struct SemaRecord { 34 // Intrinsic name, e.g. vadd_vv 35 std::string Name; 36 37 // Overloaded intrinsic name, could be empty if can be computed from Name 38 // e.g. vadd 39 std::string OverloadedName; 40 41 // Supported type, mask of BasicType. 42 unsigned TypeRangeMask; 43 44 // Supported LMUL. 45 unsigned Log2LMULMask; 46 47 // Required extensions for this intrinsic. 48 unsigned RequiredExtensions; 49 50 // Prototype for this intrinsic. 51 SmallVector<PrototypeDescriptor> Prototype; 52 53 // Suffix of intrinsic name. 54 SmallVector<PrototypeDescriptor> Suffix; 55 56 // Suffix of overloaded intrinsic name. 57 SmallVector<PrototypeDescriptor> OverloadedSuffix; 58 59 // Number of field, large than 1 if it's segment load/store. 60 unsigned NF; 61 62 bool HasMasked :1; 63 bool HasVL :1; 64 bool HasMaskedOffOperand :1; 65 }; 66 67 // Compressed function signature table. 68 class SemaSignatureTable { 69 private: 70 std::vector<PrototypeDescriptor> SignatureTable; 71 72 void insert(ArrayRef<PrototypeDescriptor> Signature); 73 74 public: 75 static constexpr unsigned INVALID_INDEX = ~0U; 76 77 // Create compressed signature table from SemaRecords. 78 void init(ArrayRef<SemaRecord> SemaRecords); 79 80 // Query the Signature, return INVALID_INDEX if not found. 81 unsigned getIndex(ArrayRef<PrototypeDescriptor> Signature); 82 83 /// Print signature table in RVVHeader Record to \p OS 84 void print(raw_ostream &OS); 85 }; 86 87 class RVVEmitter { 88 private: 89 RecordKeeper &Records; 90 91 public: 92 RVVEmitter(RecordKeeper &R) : Records(R) {} 93 94 /// Emit riscv_vector.h 95 void createHeader(raw_ostream &o); 96 97 /// Emit all the __builtin prototypes and code needed by Sema. 98 void createBuiltins(raw_ostream &o); 99 100 /// Emit all the information needed to map builtin -> LLVM IR intrinsic. 101 void createCodeGen(raw_ostream &o); 102 103 /// Emit all the information needed by SemaRISCVVectorLookup.cpp. 104 /// We've large number of intrinsic function for RVV, creating a customized 105 /// could speed up the compilation time. 106 void createSema(raw_ostream &o); 107 108 private: 109 /// Create all intrinsics and add them to \p Out and SemaRecords. 110 void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out, 111 std::vector<SemaRecord> *SemaRecords = nullptr); 112 /// Create all intrinsic records and SemaSignatureTable from SemaRecords. 113 void createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out, 114 SemaSignatureTable &SST, 115 ArrayRef<SemaRecord> SemaRecords); 116 117 /// Print HeaderCode in RVVHeader Record to \p Out 118 void printHeaderCode(raw_ostream &OS); 119 }; 120 121 } // namespace 122 123 static BasicType ParseBasicType(char c) { 124 switch (c) { 125 case 'c': 126 return BasicType::Int8; 127 break; 128 case 's': 129 return BasicType::Int16; 130 break; 131 case 'i': 132 return BasicType::Int32; 133 break; 134 case 'l': 135 return BasicType::Int64; 136 break; 137 case 'x': 138 return BasicType::Float16; 139 break; 140 case 'f': 141 return BasicType::Float32; 142 break; 143 case 'd': 144 return BasicType::Float64; 145 break; 146 147 default: 148 return BasicType::Unknown; 149 } 150 } 151 152 void emitCodeGenSwitchBody(const RVVIntrinsic *RVVI, raw_ostream &OS) { 153 if (!RVVI->getIRName().empty()) 154 OS << " ID = Intrinsic::riscv_" + RVVI->getIRName() + ";\n"; 155 if (RVVI->getNF() >= 2) 156 OS << " NF = " + utostr(RVVI->getNF()) + ";\n"; 157 if (RVVI->hasManualCodegen()) { 158 OS << RVVI->getManualCodegen(); 159 OS << "break;\n"; 160 return; 161 } 162 163 // Cast pointer operand of vector load intrinsic. 164 for (const auto &I : enumerate(RVVI->getInputTypes())) { 165 if (I.value()->isPointer()) { 166 assert(RVVI->getIntrinsicTypes().front() == -1 && 167 "RVVI should be vector load intrinsic."); 168 OS << " Ops[" << I.index() << "] = Builder.CreateBitCast(Ops["; 169 OS << I.index() << "], ResultType->getPointerTo());\n"; 170 } 171 } 172 173 if (RVVI->isMasked()) { 174 if (RVVI->hasVL()) { 175 OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n"; 176 if (RVVI->hasPolicyOperand()) 177 OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType()," 178 " TAIL_UNDISTURBED));\n"; 179 } else { 180 OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n"; 181 } 182 } else { 183 if (RVVI->hasPolicyOperand()) 184 OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(), " 185 "TAIL_UNDISTURBED));\n"; 186 else if (RVVI->hasPassthruOperand()) { 187 OS << " Ops.push_back(llvm::UndefValue::get(ResultType));\n"; 188 OS << " std::rotate(Ops.rbegin(), Ops.rbegin() + 1, Ops.rend());\n"; 189 } 190 } 191 192 OS << " IntrinsicTypes = {"; 193 ListSeparator LS; 194 for (const auto &Idx : RVVI->getIntrinsicTypes()) { 195 if (Idx == -1) 196 OS << LS << "ResultType"; 197 else 198 OS << LS << "Ops[" << Idx << "]->getType()"; 199 } 200 201 // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is 202 // always last operand. 203 if (RVVI->hasVL()) 204 OS << ", Ops.back()->getType()"; 205 OS << "};\n"; 206 OS << " break;\n"; 207 } 208 209 //===----------------------------------------------------------------------===// 210 // SemaSignatureTable implementation 211 //===----------------------------------------------------------------------===// 212 void SemaSignatureTable::init(ArrayRef<SemaRecord> SemaRecords) { 213 // Sort signature entries by length, let longer signature insert first, to 214 // make it more possible to reuse table entries, that can reduce ~10% table 215 // size. 216 struct Compare { 217 bool operator()(const SmallVector<PrototypeDescriptor> &A, 218 const SmallVector<PrototypeDescriptor> &B) const { 219 if (A.size() != B.size()) 220 return A.size() > B.size(); 221 222 size_t Len = A.size(); 223 for (size_t i = 0; i < Len; ++i) { 224 if (A[i] != B[i]) 225 return A[i] < B[i]; 226 } 227 228 return false; 229 } 230 }; 231 232 std::set<SmallVector<PrototypeDescriptor>, Compare> Signatures; 233 auto InsertToSignatureSet = 234 [&](const SmallVector<PrototypeDescriptor> &Signature) { 235 if (Signature.empty()) 236 return; 237 238 Signatures.insert(Signature); 239 }; 240 241 assert(!SemaRecords.empty()); 242 243 llvm::for_each(SemaRecords, [&](const SemaRecord &SR) { 244 InsertToSignatureSet(SR.Prototype); 245 InsertToSignatureSet(SR.Suffix); 246 InsertToSignatureSet(SR.OverloadedSuffix); 247 }); 248 249 llvm::for_each(Signatures, [this](auto &Sig) { insert(Sig); }); 250 } 251 252 void SemaSignatureTable::insert(ArrayRef<PrototypeDescriptor> Signature) { 253 if (getIndex(Signature) != INVALID_INDEX) 254 return; 255 256 // Insert Signature into SignatureTable if not found in the table. 257 SignatureTable.insert(SignatureTable.begin(), Signature.begin(), 258 Signature.end()); 259 } 260 261 unsigned SemaSignatureTable::getIndex(ArrayRef<PrototypeDescriptor> Signature) { 262 // Empty signature could be point into any index since there is length 263 // field when we use, so just always point it to 0. 264 if (Signature.empty()) 265 return 0; 266 267 // Checking Signature already in table or not. 268 if (Signature.size() < SignatureTable.size()) { 269 size_t Bound = SignatureTable.size() - Signature.size() + 1; 270 for (size_t Index = 0; Index < Bound; ++Index) { 271 if (equal(Signature.begin(), Signature.end(), 272 SignatureTable.begin() + Index)) 273 return Index; 274 } 275 } 276 277 return INVALID_INDEX; 278 } 279 280 void SemaSignatureTable::print(raw_ostream &OS) { 281 for (const auto &Sig : SignatureTable) 282 OS << "PrototypeDescriptor(" << static_cast<int>(Sig.PT) << ", " 283 << static_cast<int>(Sig.VTM) << ", " << static_cast<int>(Sig.TM) 284 << "),\n"; 285 } 286 287 //===----------------------------------------------------------------------===// 288 // RVVEmitter implementation 289 //===----------------------------------------------------------------------===// 290 void RVVEmitter::createHeader(raw_ostream &OS) { 291 292 OS << "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics " 293 "-------------------===\n" 294 " *\n" 295 " *\n" 296 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " 297 "Exceptions.\n" 298 " * See https://llvm.org/LICENSE.txt for license information.\n" 299 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 300 " *\n" 301 " *===-----------------------------------------------------------------" 302 "------===\n" 303 " */\n\n"; 304 305 OS << "#ifndef __RISCV_VECTOR_H\n"; 306 OS << "#define __RISCV_VECTOR_H\n\n"; 307 308 OS << "#include <stdint.h>\n"; 309 OS << "#include <stddef.h>\n\n"; 310 311 OS << "#ifndef __riscv_vector\n"; 312 OS << "#error \"Vector intrinsics require the vector extension.\"\n"; 313 OS << "#endif\n\n"; 314 315 OS << "#ifdef __cplusplus\n"; 316 OS << "extern \"C\" {\n"; 317 OS << "#endif\n\n"; 318 319 OS << "#pragma clang riscv intrinsic vector\n\n"; 320 321 printHeaderCode(OS); 322 323 auto printType = [&](auto T) { 324 OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr() 325 << ";\n"; 326 }; 327 328 constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3}; 329 // Print RVV boolean types. 330 for (int Log2LMUL : Log2LMULs) { 331 auto T = RVVType::computeType(BasicType::Int8, Log2LMUL, 332 PrototypeDescriptor::Mask); 333 if (T) 334 printType(T.value()); 335 } 336 // Print RVV int/float types. 337 for (char I : StringRef("csil")) { 338 BasicType BT = ParseBasicType(I); 339 for (int Log2LMUL : Log2LMULs) { 340 auto T = RVVType::computeType(BT, Log2LMUL, PrototypeDescriptor::Vector); 341 if (T) { 342 printType(T.value()); 343 auto UT = RVVType::computeType( 344 BT, Log2LMUL, 345 PrototypeDescriptor(BaseTypeModifier::Vector, 346 VectorTypeModifier::NoModifier, 347 TypeModifier::UnsignedInteger)); 348 printType(UT.value()); 349 } 350 } 351 } 352 OS << "#if defined(__riscv_zvfh)\n"; 353 for (int Log2LMUL : Log2LMULs) { 354 auto T = RVVType::computeType(BasicType::Float16, Log2LMUL, 355 PrototypeDescriptor::Vector); 356 if (T) 357 printType(T.value()); 358 } 359 OS << "#endif\n"; 360 361 OS << "#if (__riscv_v_elen_fp >= 32)\n"; 362 for (int Log2LMUL : Log2LMULs) { 363 auto T = RVVType::computeType(BasicType::Float32, Log2LMUL, 364 PrototypeDescriptor::Vector); 365 if (T) 366 printType(T.value()); 367 } 368 OS << "#endif\n"; 369 370 OS << "#if (__riscv_v_elen_fp >= 64)\n"; 371 for (int Log2LMUL : Log2LMULs) { 372 auto T = RVVType::computeType(BasicType::Float64, Log2LMUL, 373 PrototypeDescriptor::Vector); 374 if (T) 375 printType(T.value()); 376 } 377 OS << "#endif\n\n"; 378 379 OS << "#define __riscv_v_intrinsic_overloading 1\n"; 380 381 OS << "\n#ifdef __cplusplus\n"; 382 OS << "}\n"; 383 OS << "#endif // __cplusplus\n"; 384 OS << "#endif // __RISCV_VECTOR_H\n"; 385 } 386 387 void RVVEmitter::createBuiltins(raw_ostream &OS) { 388 std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 389 createRVVIntrinsics(Defs); 390 391 // Map to keep track of which builtin names have already been emitted. 392 StringMap<RVVIntrinsic *> BuiltinMap; 393 394 OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n"; 395 OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, " 396 "ATTRS, \"zve32x\")\n"; 397 OS << "#endif\n"; 398 for (auto &Def : Defs) { 399 auto P = 400 BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); 401 if (!P.second) { 402 // Verf that this would have produced the same builtin definition. 403 if (P.first->second->hasBuiltinAlias() != Def->hasBuiltinAlias()) 404 PrintFatalError("Builtin with same name has different hasAutoDef"); 405 else if (!Def->hasBuiltinAlias() && 406 P.first->second->getBuiltinTypeStr() != Def->getBuiltinTypeStr()) 407 PrintFatalError("Builtin with same name has different type string"); 408 continue; 409 } 410 OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getBuiltinName() << ",\""; 411 if (!Def->hasBuiltinAlias()) 412 OS << Def->getBuiltinTypeStr(); 413 OS << "\", \"n\")\n"; 414 } 415 OS << "#undef RISCVV_BUILTIN\n"; 416 } 417 418 void RVVEmitter::createCodeGen(raw_ostream &OS) { 419 std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 420 createRVVIntrinsics(Defs); 421 // IR name could be empty, use the stable sort preserves the relative order. 422 llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A, 423 const std::unique_ptr<RVVIntrinsic> &B) { 424 return A->getIRName() < B->getIRName(); 425 }); 426 427 // Map to keep track of which builtin names have already been emitted. 428 StringMap<RVVIntrinsic *> BuiltinMap; 429 430 // Print switch body when the ir name or ManualCodegen changes from previous 431 // iteration. 432 RVVIntrinsic *PrevDef = Defs.begin()->get(); 433 for (auto &Def : Defs) { 434 StringRef CurIRName = Def->getIRName(); 435 if (CurIRName != PrevDef->getIRName() || 436 (Def->getManualCodegen() != PrevDef->getManualCodegen())) { 437 emitCodeGenSwitchBody(PrevDef, OS); 438 } 439 PrevDef = Def.get(); 440 441 auto P = 442 BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); 443 if (P.second) { 444 OS << "case RISCVVector::BI__builtin_rvv_" << Def->getBuiltinName() 445 << ":\n"; 446 continue; 447 } 448 449 if (P.first->second->getIRName() != Def->getIRName()) 450 PrintFatalError("Builtin with same name has different IRName"); 451 else if (P.first->second->getManualCodegen() != Def->getManualCodegen()) 452 PrintFatalError("Builtin with same name has different ManualCodegen"); 453 else if (P.first->second->getNF() != Def->getNF()) 454 PrintFatalError("Builtin with same name has different NF"); 455 else if (P.first->second->isMasked() != Def->isMasked()) 456 PrintFatalError("Builtin with same name has different isMasked"); 457 else if (P.first->second->hasVL() != Def->hasVL()) 458 PrintFatalError("Builtin with same name has different hasVL"); 459 else if (P.first->second->getPolicyScheme() != Def->getPolicyScheme()) 460 PrintFatalError("Builtin with same name has different getPolicyScheme"); 461 else if (P.first->second->getIntrinsicTypes() != Def->getIntrinsicTypes()) 462 PrintFatalError("Builtin with same name has different IntrinsicTypes"); 463 } 464 emitCodeGenSwitchBody(Defs.back().get(), OS); 465 OS << "\n"; 466 } 467 468 void RVVEmitter::createRVVIntrinsics( 469 std::vector<std::unique_ptr<RVVIntrinsic>> &Out, 470 std::vector<SemaRecord> *SemaRecords) { 471 std::vector<Record *> RV = Records.getAllDerivedDefinitions("RVVBuiltin"); 472 for (auto *R : RV) { 473 StringRef Name = R->getValueAsString("Name"); 474 StringRef SuffixProto = R->getValueAsString("Suffix"); 475 StringRef OverloadedName = R->getValueAsString("OverloadedName"); 476 StringRef OverloadedSuffixProto = R->getValueAsString("OverloadedSuffix"); 477 StringRef Prototypes = R->getValueAsString("Prototype"); 478 StringRef TypeRange = R->getValueAsString("TypeRange"); 479 bool HasMasked = R->getValueAsBit("HasMasked"); 480 bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand"); 481 bool HasVL = R->getValueAsBit("HasVL"); 482 Record *MPSRecord = R->getValueAsDef("MaskedPolicyScheme"); 483 auto MaskedPolicyScheme = 484 static_cast<PolicyScheme>(MPSRecord->getValueAsInt("Value")); 485 Record *UMPSRecord = R->getValueAsDef("UnMaskedPolicyScheme"); 486 auto UnMaskedPolicyScheme = 487 static_cast<PolicyScheme>(UMPSRecord->getValueAsInt("Value")); 488 bool HasUnMaskedOverloaded = R->getValueAsBit("HasUnMaskedOverloaded"); 489 std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL"); 490 bool HasBuiltinAlias = R->getValueAsBit("HasBuiltinAlias"); 491 StringRef ManualCodegen = R->getValueAsString("ManualCodegen"); 492 StringRef MaskedManualCodegen = R->getValueAsString("MaskedManualCodegen"); 493 std::vector<int64_t> IntrinsicTypes = 494 R->getValueAsListOfInts("IntrinsicTypes"); 495 std::vector<StringRef> RequiredFeatures = 496 R->getValueAsListOfStrings("RequiredFeatures"); 497 StringRef IRName = R->getValueAsString("IRName"); 498 StringRef MaskedIRName = R->getValueAsString("MaskedIRName"); 499 unsigned NF = R->getValueAsInt("NF"); 500 501 // Parse prototype and create a list of primitive type with transformers 502 // (operand) in Prototype. Prototype[0] is output operand. 503 SmallVector<PrototypeDescriptor> BasicPrototype = 504 parsePrototypes(Prototypes); 505 506 SmallVector<PrototypeDescriptor> SuffixDesc = parsePrototypes(SuffixProto); 507 SmallVector<PrototypeDescriptor> OverloadedSuffixDesc = 508 parsePrototypes(OverloadedSuffixProto); 509 510 // Compute Builtin types 511 auto Prototype = RVVIntrinsic::computeBuiltinTypes( 512 BasicPrototype, /*IsMasked=*/false, /*HasMaskedOffOperand=*/false, 513 HasVL, NF); 514 auto MaskedPrototype = RVVIntrinsic::computeBuiltinTypes( 515 BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, NF); 516 517 // Create Intrinsics for each type and LMUL. 518 for (char I : TypeRange) { 519 for (int Log2LMUL : Log2LMULList) { 520 BasicType BT = ParseBasicType(I); 521 Optional<RVVTypes> Types = 522 RVVType::computeTypes(BT, Log2LMUL, NF, Prototype); 523 // Ignored to create new intrinsic if there are any illegal types. 524 if (!Types) 525 continue; 526 527 auto SuffixStr = RVVIntrinsic::getSuffixStr(BT, Log2LMUL, SuffixDesc); 528 auto OverloadedSuffixStr = 529 RVVIntrinsic::getSuffixStr(BT, Log2LMUL, OverloadedSuffixDesc); 530 // Create a unmasked intrinsic 531 Out.push_back(std::make_unique<RVVIntrinsic>( 532 Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName, 533 /*IsMasked=*/false, /*HasMaskedOffOperand=*/false, HasVL, 534 UnMaskedPolicyScheme, HasUnMaskedOverloaded, HasBuiltinAlias, 535 ManualCodegen, *Types, IntrinsicTypes, RequiredFeatures, NF)); 536 if (HasMasked) { 537 // Create a masked intrinsic 538 Optional<RVVTypes> MaskTypes = 539 RVVType::computeTypes(BT, Log2LMUL, NF, MaskedPrototype); 540 Out.push_back(std::make_unique<RVVIntrinsic>( 541 Name, SuffixStr, OverloadedName, OverloadedSuffixStr, 542 MaskedIRName, 543 /*IsMasked=*/true, HasMaskedOffOperand, HasVL, MaskedPolicyScheme, 544 HasUnMaskedOverloaded, HasBuiltinAlias, MaskedManualCodegen, 545 *MaskTypes, IntrinsicTypes, RequiredFeatures, NF)); 546 } 547 } // end for Log2LMULList 548 } // end for TypeRange 549 550 // We don't emit vsetvli and vsetvlimax for SemaRecord. 551 // They are written in riscv_vector.td and will emit those marco define in 552 // riscv_vector.h 553 if (Name == "vsetvli" || Name == "vsetvlimax") 554 continue; 555 556 if (!SemaRecords) 557 continue; 558 559 // Create SemaRecord 560 SemaRecord SR; 561 SR.Name = Name.str(); 562 SR.OverloadedName = OverloadedName.str(); 563 BasicType TypeRangeMask = BasicType::Unknown; 564 for (char I : TypeRange) 565 TypeRangeMask |= ParseBasicType(I); 566 567 SR.TypeRangeMask = static_cast<unsigned>(TypeRangeMask); 568 569 unsigned Log2LMULMask = 0; 570 for (int Log2LMUL : Log2LMULList) 571 Log2LMULMask |= 1 << (Log2LMUL + 3); 572 573 SR.Log2LMULMask = Log2LMULMask; 574 575 SR.RequiredExtensions = 0; 576 for (auto RequiredFeature : RequiredFeatures) { 577 RVVRequire RequireExt = StringSwitch<RVVRequire>(RequiredFeature) 578 .Case("RV64", RVV_REQ_RV64) 579 .Case("FullMultiply", RVV_REQ_FullMultiply) 580 .Default(RVV_REQ_None); 581 assert(RequireExt != RVV_REQ_None && "Unrecognized required feature?"); 582 SR.RequiredExtensions |= RequireExt; 583 } 584 585 SR.NF = NF; 586 SR.HasMasked = HasMasked; 587 SR.HasVL = HasVL; 588 SR.HasMaskedOffOperand = HasMaskedOffOperand; 589 SR.Prototype = std::move(BasicPrototype); 590 SR.Suffix = parsePrototypes(SuffixProto); 591 SR.OverloadedSuffix = parsePrototypes(OverloadedSuffixProto); 592 593 SemaRecords->push_back(SR); 594 } 595 } 596 597 void RVVEmitter::printHeaderCode(raw_ostream &OS) { 598 std::vector<Record *> RVVHeaders = 599 Records.getAllDerivedDefinitions("RVVHeader"); 600 for (auto *R : RVVHeaders) { 601 StringRef HeaderCodeStr = R->getValueAsString("HeaderCode"); 602 OS << HeaderCodeStr.str(); 603 } 604 } 605 606 void RVVEmitter::createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out, 607 SemaSignatureTable &SST, 608 ArrayRef<SemaRecord> SemaRecords) { 609 SST.init(SemaRecords); 610 611 for (const auto &SR : SemaRecords) { 612 Out.emplace_back(RVVIntrinsicRecord()); 613 RVVIntrinsicRecord &R = Out.back(); 614 R.Name = SR.Name.c_str(); 615 R.OverloadedName = SR.OverloadedName.c_str(); 616 R.PrototypeIndex = SST.getIndex(SR.Prototype); 617 R.SuffixIndex = SST.getIndex(SR.Suffix); 618 R.OverloadedSuffixIndex = SST.getIndex(SR.OverloadedSuffix); 619 R.PrototypeLength = SR.Prototype.size(); 620 R.SuffixLength = SR.Suffix.size(); 621 R.OverloadedSuffixSize = SR.OverloadedSuffix.size(); 622 R.RequiredExtensions = SR.RequiredExtensions; 623 R.TypeRangeMask = SR.TypeRangeMask; 624 R.Log2LMULMask = SR.Log2LMULMask; 625 R.NF = SR.NF; 626 R.HasMasked = SR.HasMasked; 627 R.HasVL = SR.HasVL; 628 R.HasMaskedOffOperand = SR.HasMaskedOffOperand; 629 630 assert(R.PrototypeIndex != 631 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 632 assert(R.SuffixIndex != 633 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 634 assert(R.OverloadedSuffixIndex != 635 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 636 } 637 } 638 639 void RVVEmitter::createSema(raw_ostream &OS) { 640 std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 641 std::vector<RVVIntrinsicRecord> RVVIntrinsicRecords; 642 SemaSignatureTable SST; 643 std::vector<SemaRecord> SemaRecords; 644 645 createRVVIntrinsics(Defs, &SemaRecords); 646 647 createRVVIntrinsicRecords(RVVIntrinsicRecords, SST, SemaRecords); 648 649 // Emit signature table for SemaRISCVVectorLookup.cpp. 650 OS << "#ifdef DECL_SIGNATURE_TABLE\n"; 651 SST.print(OS); 652 OS << "#endif\n"; 653 654 // Emit RVVIntrinsicRecords for SemaRISCVVectorLookup.cpp. 655 OS << "#ifdef DECL_INTRINSIC_RECORDS\n"; 656 for (const RVVIntrinsicRecord &Record : RVVIntrinsicRecords) 657 OS << Record; 658 OS << "#endif\n"; 659 } 660 661 namespace clang { 662 void EmitRVVHeader(RecordKeeper &Records, raw_ostream &OS) { 663 RVVEmitter(Records).createHeader(OS); 664 } 665 666 void EmitRVVBuiltins(RecordKeeper &Records, raw_ostream &OS) { 667 RVVEmitter(Records).createBuiltins(OS); 668 } 669 670 void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 671 RVVEmitter(Records).createCodeGen(OS); 672 } 673 674 void EmitRVVBuiltinSema(RecordKeeper &Records, raw_ostream &OS) { 675 RVVEmitter(Records).createSema(OS); 676 } 677 678 } // End namespace clang 679