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