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