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 // 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 155 default: 156 return BasicType::Unknown; 157 } 158 } 159 160 static VectorTypeModifier getTupleVTM(unsigned NF) { 161 assert(2 <= NF && NF <= 8 && "2 <= NF <= 8"); 162 return static_cast<VectorTypeModifier>( 163 static_cast<uint8_t>(VectorTypeModifier::Tuple2) + (NF - 2)); 164 } 165 166 void emitCodeGenSwitchBody(const RVVIntrinsic *RVVI, raw_ostream &OS) { 167 if (!RVVI->getIRName().empty()) 168 OS << " ID = Intrinsic::riscv_" + RVVI->getIRName() + ";\n"; 169 if (RVVI->getNF() >= 2) 170 OS << " NF = " + utostr(RVVI->getNF()) + ";\n"; 171 172 OS << " PolicyAttrs = " << RVVI->getPolicyAttrsBits() << ";\n"; 173 174 if (RVVI->hasManualCodegen()) { 175 OS << "IsMasked = " << (RVVI->isMasked() ? "true" : "false") << ";\n"; 176 OS << RVVI->getManualCodegen(); 177 OS << "break;\n"; 178 return; 179 } 180 181 // Cast pointer operand of vector load intrinsic. 182 for (const auto &I : enumerate(RVVI->getInputTypes())) { 183 if (I.value()->isPointer()) { 184 assert(RVVI->getIntrinsicTypes().front() == -1 && 185 "RVVI should be vector load intrinsic."); 186 OS << " Ops[" << I.index() << "] = Builder.CreateBitCast(Ops["; 187 OS << I.index() << "], ResultType->getPointerTo());\n"; 188 } 189 } 190 191 if (RVVI->isMasked()) { 192 if (RVVI->hasVL()) { 193 OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n"; 194 if (RVVI->hasPolicyOperand()) 195 OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType()," 196 " PolicyAttrs));\n"; 197 if (RVVI->hasMaskedOffOperand() && RVVI->getPolicyAttrs().isTAMAPolicy()) 198 OS << " Ops.insert(Ops.begin(), " 199 "llvm::PoisonValue::get(ResultType));\n"; 200 // Masked reduction cases. 201 if (!RVVI->hasMaskedOffOperand() && RVVI->hasPassthruOperand() && 202 RVVI->getPolicyAttrs().isTAMAPolicy()) 203 OS << " Ops.insert(Ops.begin(), " 204 "llvm::PoisonValue::get(ResultType));\n"; 205 } else { 206 OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n"; 207 } 208 } else { 209 if (RVVI->hasPolicyOperand()) 210 OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(), " 211 "PolicyAttrs));\n"; 212 else if (RVVI->hasPassthruOperand() && RVVI->getPolicyAttrs().isTAPolicy()) 213 OS << " Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));\n"; 214 } 215 216 OS << " IntrinsicTypes = {"; 217 ListSeparator LS; 218 for (const auto &Idx : RVVI->getIntrinsicTypes()) { 219 if (Idx == -1) 220 OS << LS << "ResultType"; 221 else 222 OS << LS << "Ops[" << Idx << "]->getType()"; 223 } 224 225 // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is 226 // always last operand. 227 if (RVVI->hasVL()) 228 OS << ", Ops.back()->getType()"; 229 OS << "};\n"; 230 OS << " break;\n"; 231 } 232 233 //===----------------------------------------------------------------------===// 234 // SemaSignatureTable implementation 235 //===----------------------------------------------------------------------===// 236 void SemaSignatureTable::init(ArrayRef<SemaRecord> SemaRecords) { 237 // Sort signature entries by length, let longer signature insert first, to 238 // make it more possible to reuse table entries, that can reduce ~10% table 239 // size. 240 struct Compare { 241 bool operator()(const SmallVector<PrototypeDescriptor> &A, 242 const SmallVector<PrototypeDescriptor> &B) const { 243 if (A.size() != B.size()) 244 return A.size() > B.size(); 245 246 size_t Len = A.size(); 247 for (size_t i = 0; i < Len; ++i) { 248 if (A[i] != B[i]) 249 return A[i] < B[i]; 250 } 251 252 return false; 253 } 254 }; 255 256 std::set<SmallVector<PrototypeDescriptor>, Compare> Signatures; 257 auto InsertToSignatureSet = 258 [&](const SmallVector<PrototypeDescriptor> &Signature) { 259 if (Signature.empty()) 260 return; 261 262 Signatures.insert(Signature); 263 }; 264 265 assert(!SemaRecords.empty()); 266 267 llvm::for_each(SemaRecords, [&](const SemaRecord &SR) { 268 InsertToSignatureSet(SR.Prototype); 269 InsertToSignatureSet(SR.Suffix); 270 InsertToSignatureSet(SR.OverloadedSuffix); 271 }); 272 273 llvm::for_each(Signatures, [this](auto &Sig) { 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 : 392 {BasicType::Float16, BasicType::Float32, BasicType::Float64}) { 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 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->getNF() != Def->getNF()) 486 PrintFatalError("Builtin with same name has different NF"); 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 = StringSwitch<RVVRequire>(RequiredFeature) 657 .Case("RV64", RVV_REQ_RV64) 658 .Case("Xsfvcp", RVV_REQ_Xsfvcp) 659 .Default(RVV_REQ_None); 660 assert(RequireExt != RVV_REQ_None && "Unrecognized required feature?"); 661 SR.RequiredExtensions |= RequireExt; 662 } 663 664 SR.NF = NF; 665 SR.HasMasked = HasMasked; 666 SR.HasVL = HasVL; 667 SR.HasMaskedOffOperand = HasMaskedOffOperand; 668 SR.HasTailPolicy = HasTailPolicy; 669 SR.HasMaskPolicy = HasMaskPolicy; 670 SR.UnMaskedPolicyScheme = static_cast<uint8_t>(UnMaskedPolicyScheme); 671 SR.MaskedPolicyScheme = static_cast<uint8_t>(MaskedPolicyScheme); 672 SR.Prototype = std::move(BasicPrototype); 673 SR.Suffix = parsePrototypes(SuffixProto); 674 SR.OverloadedSuffix = parsePrototypes(OverloadedSuffixProto); 675 SR.IsTuple = IsTuple; 676 SR.HasFRMRoundModeOp = HasFRMRoundModeOp; 677 678 SemaRecords->push_back(SR); 679 } 680 } 681 682 void RVVEmitter::printHeaderCode(raw_ostream &OS) { 683 std::vector<Record *> RVVHeaders = 684 Records.getAllDerivedDefinitions("RVVHeader"); 685 for (auto *R : RVVHeaders) { 686 StringRef HeaderCodeStr = R->getValueAsString("HeaderCode"); 687 OS << HeaderCodeStr.str(); 688 } 689 } 690 691 void RVVEmitter::createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out, 692 SemaSignatureTable &SST, 693 ArrayRef<SemaRecord> SemaRecords) { 694 SST.init(SemaRecords); 695 696 for (const auto &SR : SemaRecords) { 697 Out.emplace_back(RVVIntrinsicRecord()); 698 RVVIntrinsicRecord &R = Out.back(); 699 R.Name = SR.Name.c_str(); 700 R.OverloadedName = SR.OverloadedName.c_str(); 701 R.PrototypeIndex = SST.getIndex(SR.Prototype); 702 R.SuffixIndex = SST.getIndex(SR.Suffix); 703 R.OverloadedSuffixIndex = SST.getIndex(SR.OverloadedSuffix); 704 R.PrototypeLength = SR.Prototype.size(); 705 R.SuffixLength = SR.Suffix.size(); 706 R.OverloadedSuffixSize = SR.OverloadedSuffix.size(); 707 R.RequiredExtensions = SR.RequiredExtensions; 708 R.TypeRangeMask = SR.TypeRangeMask; 709 R.Log2LMULMask = SR.Log2LMULMask; 710 R.NF = SR.NF; 711 R.HasMasked = SR.HasMasked; 712 R.HasVL = SR.HasVL; 713 R.HasMaskedOffOperand = SR.HasMaskedOffOperand; 714 R.HasTailPolicy = SR.HasTailPolicy; 715 R.HasMaskPolicy = SR.HasMaskPolicy; 716 R.UnMaskedPolicyScheme = SR.UnMaskedPolicyScheme; 717 R.MaskedPolicyScheme = SR.MaskedPolicyScheme; 718 R.IsTuple = SR.IsTuple; 719 R.HasFRMRoundModeOp = SR.HasFRMRoundModeOp; 720 721 assert(R.PrototypeIndex != 722 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 723 assert(R.SuffixIndex != 724 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 725 assert(R.OverloadedSuffixIndex != 726 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 727 } 728 } 729 730 void RVVEmitter::createSema(raw_ostream &OS) { 731 std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 732 std::vector<RVVIntrinsicRecord> RVVIntrinsicRecords; 733 SemaSignatureTable SST; 734 std::vector<SemaRecord> SemaRecords; 735 736 createRVVIntrinsics(Defs, &SemaRecords); 737 738 createRVVIntrinsicRecords(RVVIntrinsicRecords, SST, SemaRecords); 739 740 // Emit signature table for SemaRISCVVectorLookup.cpp. 741 OS << "#ifdef DECL_SIGNATURE_TABLE\n"; 742 SST.print(OS); 743 OS << "#endif\n"; 744 745 // Emit RVVIntrinsicRecords for SemaRISCVVectorLookup.cpp. 746 OS << "#ifdef DECL_INTRINSIC_RECORDS\n"; 747 for (const RVVIntrinsicRecord &Record : RVVIntrinsicRecords) 748 OS << Record; 749 OS << "#endif\n"; 750 } 751 752 namespace clang { 753 void EmitRVVHeader(RecordKeeper &Records, raw_ostream &OS) { 754 RVVEmitter(Records).createHeader(OS); 755 } 756 757 void EmitRVVBuiltins(RecordKeeper &Records, raw_ostream &OS) { 758 RVVEmitter(Records).createBuiltins(OS); 759 } 760 761 void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 762 RVVEmitter(Records).createCodeGen(OS); 763 } 764 765 void EmitRVVBuiltinSema(RecordKeeper &Records, raw_ostream &OS) { 766 RVVEmitter(Records).createSema(OS); 767 } 768 769 } // End namespace clang 770