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