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/StringExtras.h" 20 #include "llvm/ADT/StringMap.h" 21 #include "llvm/ADT/StringRef.h" 22 #include "llvm/ADT/StringSwitch.h" 23 #include "llvm/ADT/Twine.h" 24 #include "llvm/TableGen/Error.h" 25 #include "llvm/TableGen/Record.h" 26 #include "llvm/TableGen/StringToOffsetTable.h" 27 #include <optional> 28 29 using namespace llvm; 30 using namespace clang::RISCV; 31 32 namespace { 33 struct SemaRecord { 34 // Intrinsic name, e.g. vadd_vv 35 std::string Name; 36 37 // Overloaded intrinsic name, could be empty if can be computed from Name 38 // e.g. vadd 39 std::string OverloadedName; 40 41 // Supported type, mask of BasicType. 42 unsigned TypeRangeMask; 43 44 // Supported LMUL. 45 unsigned Log2LMULMask; 46 47 // Required extensions for this intrinsic. 48 std::string RequiredExtensions; 49 50 // Prototype for this intrinsic. 51 SmallVector<PrototypeDescriptor> Prototype; 52 53 // Suffix of intrinsic name. 54 SmallVector<PrototypeDescriptor> Suffix; 55 56 // Suffix of overloaded intrinsic name. 57 SmallVector<PrototypeDescriptor> OverloadedSuffix; 58 59 // Number of field, large than 1 if it's segment load/store. 60 unsigned NF; 61 62 bool HasMasked :1; 63 bool HasVL :1; 64 bool HasMaskedOffOperand :1; 65 bool HasTailPolicy : 1; 66 bool HasMaskPolicy : 1; 67 bool HasFRMRoundModeOp : 1; 68 bool IsTuple : 1; 69 LLVM_PREFERRED_TYPE(PolicyScheme) 70 uint8_t UnMaskedPolicyScheme : 2; 71 LLVM_PREFERRED_TYPE(PolicyScheme) 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 const RecordKeeper &Records; 98 RVVTypeCache TypeCache; 99 100 public: 101 RVVEmitter(const 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 case 'y': 156 return BasicType::BFloat16; 157 break; 158 default: 159 return BasicType::Unknown; 160 } 161 } 162 163 static VectorTypeModifier getTupleVTM(unsigned NF) { 164 assert(2 <= NF && NF <= 8 && "2 <= NF <= 8"); 165 return static_cast<VectorTypeModifier>( 166 static_cast<uint8_t>(VectorTypeModifier::Tuple2) + (NF - 2)); 167 } 168 169 static unsigned getIndexedLoadStorePtrIdx(const RVVIntrinsic *RVVI) { 170 // We need a special rule for segment load/store since the data width is not 171 // encoded in the intrinsic name itself. 172 const StringRef IRName = RVVI->getIRName(); 173 constexpr unsigned RVV_VTA = 0x1; 174 constexpr unsigned RVV_VMA = 0x2; 175 176 if (IRName.starts_with("vloxseg") || IRName.starts_with("vluxseg")) { 177 bool NoPassthru = 178 (RVVI->isMasked() && (RVVI->getPolicyAttrsBits() & RVV_VTA) && 179 (RVVI->getPolicyAttrsBits() & RVV_VMA)) || 180 (!RVVI->isMasked() && (RVVI->getPolicyAttrsBits() & RVV_VTA)); 181 return RVVI->isMasked() ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1; 182 } 183 if (IRName.starts_with("vsoxseg") || IRName.starts_with("vsuxseg")) 184 return RVVI->isMasked() ? 1 : 0; 185 186 return (unsigned)-1; 187 } 188 189 // This function is used to get the log2SEW of each segment load/store, this 190 // prevent to add a member to RVVIntrinsic. 191 static unsigned getSegInstLog2SEW(StringRef InstName) { 192 // clang-format off 193 // We need a special rule for indexed segment load/store since the data width 194 // is not encoded in the intrinsic name itself. 195 if (InstName.starts_with("vloxseg") || InstName.starts_with("vluxseg") || 196 InstName.starts_with("vsoxseg") || InstName.starts_with("vsuxseg")) 197 return (unsigned)-1; 198 199 #define KEY_VAL(KEY, VAL) {#KEY, VAL} 200 #define KEY_VAL_ALL_W_POLICY(KEY, VAL) \ 201 KEY_VAL(KEY, VAL), \ 202 KEY_VAL(KEY ## _tu, VAL), \ 203 KEY_VAL(KEY ## _tum, VAL), \ 204 KEY_VAL(KEY ## _tumu, VAL), \ 205 KEY_VAL(KEY ## _mu, VAL) 206 207 #define KEY_VAL_ALL_NF_BASE(MACRO_NAME, NAME, SEW, LOG2SEW, FF) \ 208 MACRO_NAME(NAME ## 2e ## SEW ## FF, LOG2SEW), \ 209 MACRO_NAME(NAME ## 3e ## SEW ## FF, LOG2SEW), \ 210 MACRO_NAME(NAME ## 4e ## SEW ## FF, LOG2SEW), \ 211 MACRO_NAME(NAME ## 5e ## SEW ## FF, LOG2SEW), \ 212 MACRO_NAME(NAME ## 6e ## SEW ## FF, LOG2SEW), \ 213 MACRO_NAME(NAME ## 7e ## SEW ## FF, LOG2SEW), \ 214 MACRO_NAME(NAME ## 8e ## SEW ## FF, LOG2SEW) 215 216 #define KEY_VAL_ALL_NF(NAME, SEW, LOG2SEW) \ 217 KEY_VAL_ALL_NF_BASE(KEY_VAL_ALL_W_POLICY, NAME, SEW, LOG2SEW,) 218 219 #define KEY_VAL_FF_ALL_NF(NAME, SEW, LOG2SEW) \ 220 KEY_VAL_ALL_NF_BASE(KEY_VAL_ALL_W_POLICY, NAME, SEW, LOG2SEW, ff) 221 222 #define KEY_VAL_ALL_NF_SEW_BASE(MACRO_NAME, NAME) \ 223 MACRO_NAME(NAME, 8, 3), \ 224 MACRO_NAME(NAME, 16, 4), \ 225 MACRO_NAME(NAME, 32, 5), \ 226 MACRO_NAME(NAME, 64, 6) 227 228 #define KEY_VAL_ALL_NF_SEW(NAME) \ 229 KEY_VAL_ALL_NF_SEW_BASE(KEY_VAL_ALL_NF, NAME) 230 231 #define KEY_VAL_FF_ALL_NF_SEW(NAME) \ 232 KEY_VAL_ALL_NF_SEW_BASE(KEY_VAL_FF_ALL_NF, NAME) 233 // clang-format on 234 235 static StringMap<unsigned> SegInsts = { 236 KEY_VAL_ALL_NF_SEW(vlseg), KEY_VAL_FF_ALL_NF_SEW(vlseg), 237 KEY_VAL_ALL_NF_SEW(vlsseg), KEY_VAL_ALL_NF_SEW(vsseg), 238 KEY_VAL_ALL_NF_SEW(vssseg)}; 239 240 #undef KEY_VAL_ALL_NF_SEW 241 #undef KEY_VAL_ALL_NF 242 #undef KEY_VAL 243 244 return SegInsts.lookup(InstName); 245 } 246 247 void emitCodeGenSwitchBody(const RVVIntrinsic *RVVI, raw_ostream &OS) { 248 if (!RVVI->getIRName().empty()) 249 OS << " ID = Intrinsic::riscv_" + RVVI->getIRName() + ";\n"; 250 251 OS << " PolicyAttrs = " << RVVI->getPolicyAttrsBits() << ";\n"; 252 OS << " SegInstSEW = " << getSegInstLog2SEW(RVVI->getOverloadedName()) 253 << ";\n"; 254 255 if (RVVI->hasManualCodegen()) { 256 OS << "IsMasked = " << (RVVI->isMasked() ? "true" : "false") << ";\n"; 257 258 // Skip the non-indexed load/store and compatible header load/store. 259 OS << "if (SegInstSEW == (unsigned)-1) {\n"; 260 OS << " auto PointeeType = E->getArg(" << getIndexedLoadStorePtrIdx(RVVI) 261 << " )->getType()->getPointeeType();\n"; 262 OS << " SegInstSEW = " 263 " llvm::Log2_64(getContext().getTypeSize(PointeeType));\n}\n"; 264 265 OS << RVVI->getManualCodegen(); 266 OS << "break;\n"; 267 return; 268 } 269 270 for (const auto &I : enumerate(RVVI->getInputTypes())) { 271 if (I.value()->isPointer()) { 272 assert(RVVI->getIntrinsicTypes().front() == -1 && 273 "RVVI should be vector load intrinsic."); 274 } 275 } 276 277 if (RVVI->isMasked()) { 278 if (RVVI->hasVL()) { 279 OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n"; 280 if (RVVI->hasPolicyOperand()) 281 OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType()," 282 " PolicyAttrs));\n"; 283 if (RVVI->hasMaskedOffOperand() && RVVI->getPolicyAttrs().isTAMAPolicy()) 284 OS << " Ops.insert(Ops.begin(), " 285 "llvm::PoisonValue::get(ResultType));\n"; 286 // Masked reduction cases. 287 if (!RVVI->hasMaskedOffOperand() && RVVI->hasPassthruOperand() && 288 RVVI->getPolicyAttrs().isTAMAPolicy()) 289 OS << " Ops.insert(Ops.begin(), " 290 "llvm::PoisonValue::get(ResultType));\n"; 291 } else { 292 OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n"; 293 } 294 } else { 295 if (RVVI->hasPolicyOperand()) 296 OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(), " 297 "PolicyAttrs));\n"; 298 else if (RVVI->hasPassthruOperand() && RVVI->getPolicyAttrs().isTAPolicy()) 299 OS << " Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));\n"; 300 } 301 302 OS << " IntrinsicTypes = {"; 303 ListSeparator LS; 304 for (const auto &Idx : RVVI->getIntrinsicTypes()) { 305 if (Idx == -1) 306 OS << LS << "ResultType"; 307 else 308 OS << LS << "Ops[" << Idx << "]->getType()"; 309 } 310 311 // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is 312 // always last operand. 313 if (RVVI->hasVL()) 314 OS << ", Ops.back()->getType()"; 315 OS << "};\n"; 316 OS << " break;\n"; 317 } 318 319 //===----------------------------------------------------------------------===// 320 // SemaSignatureTable implementation 321 //===----------------------------------------------------------------------===// 322 void SemaSignatureTable::init(ArrayRef<SemaRecord> SemaRecords) { 323 // Sort signature entries by length, let longer signature insert first, to 324 // make it more possible to reuse table entries, that can reduce ~10% table 325 // size. 326 struct Compare { 327 bool operator()(const SmallVector<PrototypeDescriptor> &A, 328 const SmallVector<PrototypeDescriptor> &B) const { 329 if (A.size() != B.size()) 330 return A.size() > B.size(); 331 332 size_t Len = A.size(); 333 for (size_t i = 0; i < Len; ++i) { 334 if (A[i] != B[i]) 335 return A[i] < B[i]; 336 } 337 338 return false; 339 } 340 }; 341 342 std::set<SmallVector<PrototypeDescriptor>, Compare> Signatures; 343 auto InsertToSignatureSet = 344 [&](const SmallVector<PrototypeDescriptor> &Signature) { 345 if (Signature.empty()) 346 return; 347 348 Signatures.insert(Signature); 349 }; 350 351 assert(!SemaRecords.empty()); 352 353 for (const SemaRecord &SR : SemaRecords) { 354 InsertToSignatureSet(SR.Prototype); 355 InsertToSignatureSet(SR.Suffix); 356 InsertToSignatureSet(SR.OverloadedSuffix); 357 } 358 359 for (auto &Sig : Signatures) 360 insert(Sig); 361 } 362 363 void SemaSignatureTable::insert(ArrayRef<PrototypeDescriptor> Signature) { 364 if (getIndex(Signature) != INVALID_INDEX) 365 return; 366 367 // Insert Signature into SignatureTable if not found in the table. 368 SignatureTable.insert(SignatureTable.begin(), Signature.begin(), 369 Signature.end()); 370 } 371 372 unsigned SemaSignatureTable::getIndex(ArrayRef<PrototypeDescriptor> Signature) { 373 // Empty signature could be point into any index since there is length 374 // field when we use, so just always point it to 0. 375 if (Signature.empty()) 376 return 0; 377 378 // Checking Signature already in table or not. 379 if (Signature.size() <= SignatureTable.size()) { 380 size_t Bound = SignatureTable.size() - Signature.size() + 1; 381 for (size_t Index = 0; Index < Bound; ++Index) { 382 if (equal(Signature.begin(), Signature.end(), 383 SignatureTable.begin() + Index)) 384 return Index; 385 } 386 } 387 388 return INVALID_INDEX; 389 } 390 391 void SemaSignatureTable::print(raw_ostream &OS) { 392 for (const auto &Sig : SignatureTable) 393 OS << "PrototypeDescriptor(" << static_cast<int>(Sig.PT) << ", " 394 << static_cast<int>(Sig.VTM) << ", " << static_cast<int>(Sig.TM) 395 << "),\n"; 396 } 397 398 //===----------------------------------------------------------------------===// 399 // RVVEmitter implementation 400 //===----------------------------------------------------------------------===// 401 void RVVEmitter::createHeader(raw_ostream &OS) { 402 403 OS << "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics " 404 "-------------------===\n" 405 " *\n" 406 " *\n" 407 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " 408 "Exceptions.\n" 409 " * See https://llvm.org/LICENSE.txt for license information.\n" 410 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 411 " *\n" 412 " *===-----------------------------------------------------------------" 413 "------===\n" 414 " */\n\n"; 415 416 OS << "#ifndef __RISCV_VECTOR_H\n"; 417 OS << "#define __RISCV_VECTOR_H\n\n"; 418 419 OS << "#include <stdint.h>\n"; 420 OS << "#include <stddef.h>\n\n"; 421 422 OS << "#ifdef __cplusplus\n"; 423 OS << "extern \"C\" {\n"; 424 OS << "#endif\n\n"; 425 426 OS << "#pragma clang riscv intrinsic vector\n\n"; 427 428 printHeaderCode(OS); 429 430 auto printType = [&](auto T) { 431 OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr() 432 << ";\n"; 433 }; 434 435 constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3}; 436 // Print RVV boolean types. 437 for (int Log2LMUL : Log2LMULs) { 438 auto T = TypeCache.computeType(BasicType::Int8, Log2LMUL, 439 PrototypeDescriptor::Mask); 440 if (T) 441 printType(*T); 442 } 443 // Print RVV int/float types. 444 for (char I : StringRef("csil")) { 445 BasicType BT = ParseBasicType(I); 446 for (int Log2LMUL : Log2LMULs) { 447 auto T = TypeCache.computeType(BT, Log2LMUL, PrototypeDescriptor::Vector); 448 if (T) { 449 printType(*T); 450 auto UT = TypeCache.computeType( 451 BT, Log2LMUL, 452 PrototypeDescriptor(BaseTypeModifier::Vector, 453 VectorTypeModifier::NoModifier, 454 TypeModifier::UnsignedInteger)); 455 printType(*UT); 456 } 457 for (int NF = 2; NF <= 8; ++NF) { 458 auto TupleT = TypeCache.computeType( 459 BT, Log2LMUL, 460 PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF), 461 TypeModifier::SignedInteger)); 462 auto TupleUT = TypeCache.computeType( 463 BT, Log2LMUL, 464 PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF), 465 TypeModifier::UnsignedInteger)); 466 if (TupleT) 467 printType(*TupleT); 468 if (TupleUT) 469 printType(*TupleUT); 470 } 471 } 472 } 473 474 for (BasicType BT : {BasicType::Float16, BasicType::Float32, 475 BasicType::Float64, BasicType::BFloat16}) { 476 for (int Log2LMUL : Log2LMULs) { 477 auto T = TypeCache.computeType(BT, Log2LMUL, PrototypeDescriptor::Vector); 478 if (T) 479 printType(*T); 480 for (int NF = 2; NF <= 8; ++NF) { 481 auto TupleT = TypeCache.computeType( 482 BT, Log2LMUL, 483 PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF), 484 (BT == BasicType::BFloat16 485 ? TypeModifier::BFloat 486 : TypeModifier::Float))); 487 if (TupleT) 488 printType(*TupleT); 489 } 490 } 491 } 492 493 OS << "\n#ifdef __cplusplus\n"; 494 OS << "}\n"; 495 OS << "#endif // __cplusplus\n"; 496 OS << "#endif // __RISCV_VECTOR_H\n"; 497 } 498 499 void RVVEmitter::createBuiltins(raw_ostream &OS) { 500 std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 501 createRVVIntrinsics(Defs); 502 503 llvm::StringToOffsetTable Table; 504 // Ensure offset zero is the empty string. 505 Table.GetOrAddStringOffset(""); 506 // Hard coded strings used in the builtin structures. 507 Table.GetOrAddStringOffset("n"); 508 Table.GetOrAddStringOffset("zve32x"); 509 510 // Map to unique the builtin names. 511 StringMap<RVVIntrinsic *> BuiltinMap; 512 std::vector<RVVIntrinsic *> UniqueDefs; 513 for (auto &Def : Defs) { 514 auto P = BuiltinMap.insert({Def->getBuiltinName(), Def.get()}); 515 if (P.second) { 516 Table.GetOrAddStringOffset(Def->getBuiltinName()); 517 if (!Def->hasBuiltinAlias()) 518 Table.GetOrAddStringOffset(Def->getBuiltinTypeStr()); 519 UniqueDefs.push_back(Def.get()); 520 continue; 521 } 522 523 // Verf that this would have produced the same builtin definition. 524 if (P.first->second->hasBuiltinAlias() != Def->hasBuiltinAlias()) 525 PrintFatalError("Builtin with same name has different hasAutoDef"); 526 else if (!Def->hasBuiltinAlias() && 527 P.first->second->getBuiltinTypeStr() != Def->getBuiltinTypeStr()) 528 PrintFatalError("Builtin with same name has different type string"); 529 } 530 531 // Emit the enumerators of RVV builtins. Note that these are emitted without 532 // any outer context to enable concatenating them. 533 OS << "// RISCV Vector builtin enumerators\n"; 534 OS << "#ifdef GET_RISCVV_BUILTIN_ENUMERATORS\n"; 535 for (RVVIntrinsic *Def : UniqueDefs) 536 OS << " BI__builtin_rvv_" << Def->getBuiltinName() << ",\n"; 537 OS << "#endif // GET_RISCVV_BUILTIN_ENUMERATORS\n\n"; 538 539 // Emit the string table for the RVV builtins. 540 OS << "// RISCV Vector builtin enumerators\n"; 541 OS << "#ifdef GET_RISCVV_BUILTIN_STR_TABLE\n"; 542 Table.EmitStringTableDef(OS, "BuiltinStrings"); 543 OS << "#endif // GET_RISCVV_BUILTIN_STR_TABLE\n\n"; 544 545 // Emit the info structs of RVV builtins. Note that these are emitted without 546 // any outer context to enable concatenating them. 547 OS << "// RISCV Vector builtin infos\n"; 548 OS << "#ifdef GET_RISCVV_BUILTIN_INFOS\n"; 549 for (RVVIntrinsic *Def : UniqueDefs) { 550 OS << " Builtin::Info{Builtin::Info::StrOffsets{" 551 << Table.GetStringOffset(Def->getBuiltinName()) << " /* " 552 << Def->getBuiltinName() << " */, "; 553 if (Def->hasBuiltinAlias()) { 554 OS << "0, "; 555 } else { 556 OS << Table.GetStringOffset(Def->getBuiltinTypeStr()) << " /* " 557 << Def->getBuiltinTypeStr() << " */, "; 558 } 559 OS << Table.GetStringOffset("n") << " /* n */, "; 560 OS << Table.GetStringOffset("zve32x") << " /* zve32x */}, "; 561 562 OS << "HeaderDesc::NO_HEADER, ALL_LANGUAGES},\n"; 563 } 564 OS << "#endif // GET_RISCVV_BUILTIN_INFOS\n\n"; 565 } 566 567 void RVVEmitter::createCodeGen(raw_ostream &OS) { 568 std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 569 createRVVIntrinsics(Defs); 570 // IR name could be empty, use the stable sort preserves the relative order. 571 stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A, 572 const std::unique_ptr<RVVIntrinsic> &B) { 573 if (A->getIRName() == B->getIRName()) 574 return (A->getPolicyAttrs() < B->getPolicyAttrs()); 575 return (A->getIRName() < B->getIRName()); 576 }); 577 578 // Map to keep track of which builtin names have already been emitted. 579 StringMap<RVVIntrinsic *> BuiltinMap; 580 581 // Print switch body when the ir name, ManualCodegen, policy or log2sew 582 // changes from previous iteration. 583 RVVIntrinsic *PrevDef = Defs.begin()->get(); 584 for (auto &Def : Defs) { 585 StringRef CurIRName = Def->getIRName(); 586 if (CurIRName != PrevDef->getIRName() || 587 (Def->getManualCodegen() != PrevDef->getManualCodegen()) || 588 (Def->getPolicyAttrs() != PrevDef->getPolicyAttrs()) || 589 (getSegInstLog2SEW(Def->getOverloadedName()) != 590 getSegInstLog2SEW(PrevDef->getOverloadedName()))) { 591 emitCodeGenSwitchBody(PrevDef, OS); 592 } 593 PrevDef = Def.get(); 594 595 auto P = 596 BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); 597 if (P.second) { 598 OS << "case RISCVVector::BI__builtin_rvv_" << Def->getBuiltinName() 599 << ":\n"; 600 continue; 601 } 602 603 if (P.first->second->getIRName() != Def->getIRName()) 604 PrintFatalError("Builtin with same name has different IRName"); 605 else if (P.first->second->getManualCodegen() != Def->getManualCodegen()) 606 PrintFatalError("Builtin with same name has different ManualCodegen"); 607 else if (P.first->second->isMasked() != Def->isMasked()) 608 PrintFatalError("Builtin with same name has different isMasked"); 609 else if (P.first->second->hasVL() != Def->hasVL()) 610 PrintFatalError("Builtin with same name has different hasVL"); 611 else if (P.first->second->getPolicyScheme() != Def->getPolicyScheme()) 612 PrintFatalError("Builtin with same name has different getPolicyScheme"); 613 else if (P.first->second->getIntrinsicTypes() != Def->getIntrinsicTypes()) 614 PrintFatalError("Builtin with same name has different IntrinsicTypes"); 615 } 616 emitCodeGenSwitchBody(Defs.back().get(), OS); 617 OS << "\n"; 618 } 619 620 void RVVEmitter::createRVVIntrinsics( 621 std::vector<std::unique_ptr<RVVIntrinsic>> &Out, 622 std::vector<SemaRecord> *SemaRecords) { 623 for (const Record *R : Records.getAllDerivedDefinitions("RVVBuiltin")) { 624 StringRef Name = R->getValueAsString("Name"); 625 StringRef SuffixProto = R->getValueAsString("Suffix"); 626 StringRef OverloadedName = R->getValueAsString("OverloadedName"); 627 StringRef OverloadedSuffixProto = R->getValueAsString("OverloadedSuffix"); 628 StringRef Prototypes = R->getValueAsString("Prototype"); 629 StringRef TypeRange = R->getValueAsString("TypeRange"); 630 bool HasMasked = R->getValueAsBit("HasMasked"); 631 bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand"); 632 bool HasVL = R->getValueAsBit("HasVL"); 633 const Record *MPSRecord = R->getValueAsDef("MaskedPolicyScheme"); 634 auto MaskedPolicyScheme = 635 static_cast<PolicyScheme>(MPSRecord->getValueAsInt("Value")); 636 const Record *UMPSRecord = R->getValueAsDef("UnMaskedPolicyScheme"); 637 auto UnMaskedPolicyScheme = 638 static_cast<PolicyScheme>(UMPSRecord->getValueAsInt("Value")); 639 std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL"); 640 bool HasTailPolicy = R->getValueAsBit("HasTailPolicy"); 641 bool HasMaskPolicy = R->getValueAsBit("HasMaskPolicy"); 642 bool SupportOverloading = R->getValueAsBit("SupportOverloading"); 643 bool HasBuiltinAlias = R->getValueAsBit("HasBuiltinAlias"); 644 StringRef ManualCodegen = R->getValueAsString("ManualCodegen"); 645 std::vector<int64_t> IntrinsicTypes = 646 R->getValueAsListOfInts("IntrinsicTypes"); 647 std::vector<StringRef> RequiredFeatures = 648 R->getValueAsListOfStrings("RequiredFeatures"); 649 StringRef IRName = R->getValueAsString("IRName"); 650 StringRef MaskedIRName = R->getValueAsString("MaskedIRName"); 651 unsigned NF = R->getValueAsInt("NF"); 652 bool IsTuple = R->getValueAsBit("IsTuple"); 653 bool HasFRMRoundModeOp = R->getValueAsBit("HasFRMRoundModeOp"); 654 655 const Policy DefaultPolicy; 656 SmallVector<Policy> SupportedUnMaskedPolicies = 657 RVVIntrinsic::getSupportedUnMaskedPolicies(); 658 SmallVector<Policy> SupportedMaskedPolicies = 659 RVVIntrinsic::getSupportedMaskedPolicies(HasTailPolicy, HasMaskPolicy); 660 661 // Parse prototype and create a list of primitive type with transformers 662 // (operand) in Prototype. Prototype[0] is output operand. 663 SmallVector<PrototypeDescriptor> BasicPrototype = 664 parsePrototypes(Prototypes); 665 666 SmallVector<PrototypeDescriptor> SuffixDesc = parsePrototypes(SuffixProto); 667 SmallVector<PrototypeDescriptor> OverloadedSuffixDesc = 668 parsePrototypes(OverloadedSuffixProto); 669 670 // Compute Builtin types 671 auto Prototype = RVVIntrinsic::computeBuiltinTypes( 672 BasicPrototype, /*IsMasked=*/false, 673 /*HasMaskedOffOperand=*/false, HasVL, NF, UnMaskedPolicyScheme, 674 DefaultPolicy, IsTuple); 675 SmallVector<PrototypeDescriptor> MaskedPrototype; 676 if (HasMasked) 677 MaskedPrototype = RVVIntrinsic::computeBuiltinTypes( 678 BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, NF, 679 MaskedPolicyScheme, DefaultPolicy, IsTuple); 680 681 // Create Intrinsics for each type and LMUL. 682 for (char I : TypeRange) { 683 for (int Log2LMUL : Log2LMULList) { 684 BasicType BT = ParseBasicType(I); 685 std::optional<RVVTypes> Types = 686 TypeCache.computeTypes(BT, Log2LMUL, NF, Prototype); 687 // Ignored to create new intrinsic if there are any illegal types. 688 if (!Types) 689 continue; 690 691 auto SuffixStr = 692 RVVIntrinsic::getSuffixStr(TypeCache, BT, Log2LMUL, SuffixDesc); 693 auto OverloadedSuffixStr = RVVIntrinsic::getSuffixStr( 694 TypeCache, BT, Log2LMUL, OverloadedSuffixDesc); 695 // Create a unmasked intrinsic 696 Out.push_back(std::make_unique<RVVIntrinsic>( 697 Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName, 698 /*IsMasked=*/false, /*HasMaskedOffOperand=*/false, HasVL, 699 UnMaskedPolicyScheme, SupportOverloading, HasBuiltinAlias, 700 ManualCodegen, *Types, IntrinsicTypes, NF, DefaultPolicy, 701 HasFRMRoundModeOp)); 702 if (UnMaskedPolicyScheme != PolicyScheme::SchemeNone) 703 for (auto P : SupportedUnMaskedPolicies) { 704 SmallVector<PrototypeDescriptor> PolicyPrototype = 705 RVVIntrinsic::computeBuiltinTypes( 706 BasicPrototype, /*IsMasked=*/false, 707 /*HasMaskedOffOperand=*/false, HasVL, NF, 708 UnMaskedPolicyScheme, P, IsTuple); 709 std::optional<RVVTypes> PolicyTypes = 710 TypeCache.computeTypes(BT, Log2LMUL, NF, PolicyPrototype); 711 Out.push_back(std::make_unique<RVVIntrinsic>( 712 Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName, 713 /*IsMask=*/false, /*HasMaskedOffOperand=*/false, HasVL, 714 UnMaskedPolicyScheme, SupportOverloading, HasBuiltinAlias, 715 ManualCodegen, *PolicyTypes, IntrinsicTypes, NF, P, 716 HasFRMRoundModeOp)); 717 } 718 if (!HasMasked) 719 continue; 720 // Create a masked intrinsic 721 std::optional<RVVTypes> MaskTypes = 722 TypeCache.computeTypes(BT, Log2LMUL, NF, MaskedPrototype); 723 Out.push_back(std::make_unique<RVVIntrinsic>( 724 Name, SuffixStr, OverloadedName, OverloadedSuffixStr, MaskedIRName, 725 /*IsMasked=*/true, HasMaskedOffOperand, HasVL, MaskedPolicyScheme, 726 SupportOverloading, HasBuiltinAlias, ManualCodegen, *MaskTypes, 727 IntrinsicTypes, NF, DefaultPolicy, HasFRMRoundModeOp)); 728 if (MaskedPolicyScheme == PolicyScheme::SchemeNone) 729 continue; 730 for (auto P : SupportedMaskedPolicies) { 731 SmallVector<PrototypeDescriptor> PolicyPrototype = 732 RVVIntrinsic::computeBuiltinTypes( 733 BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, 734 NF, MaskedPolicyScheme, P, IsTuple); 735 std::optional<RVVTypes> PolicyTypes = 736 TypeCache.computeTypes(BT, Log2LMUL, NF, PolicyPrototype); 737 Out.push_back(std::make_unique<RVVIntrinsic>( 738 Name, SuffixStr, OverloadedName, OverloadedSuffixStr, 739 MaskedIRName, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, 740 MaskedPolicyScheme, SupportOverloading, HasBuiltinAlias, 741 ManualCodegen, *PolicyTypes, IntrinsicTypes, NF, P, 742 HasFRMRoundModeOp)); 743 } 744 } // End for Log2LMULList 745 } // End for TypeRange 746 747 // We don't emit vsetvli and vsetvlimax for SemaRecord. 748 // They are written in riscv_vector.td and will emit those marco define in 749 // riscv_vector.h 750 if (Name == "vsetvli" || Name == "vsetvlimax") 751 continue; 752 753 if (!SemaRecords) 754 continue; 755 756 // Create SemaRecord 757 SemaRecord SR; 758 SR.Name = Name.str(); 759 SR.OverloadedName = OverloadedName.str(); 760 BasicType TypeRangeMask = BasicType::Unknown; 761 for (char I : TypeRange) 762 TypeRangeMask |= ParseBasicType(I); 763 764 SR.TypeRangeMask = static_cast<unsigned>(TypeRangeMask); 765 766 unsigned Log2LMULMask = 0; 767 for (int Log2LMUL : Log2LMULList) 768 Log2LMULMask |= 1 << (Log2LMUL + 3); 769 770 SR.Log2LMULMask = Log2LMULMask; 771 std::string RFs = 772 join(RequiredFeatures.begin(), RequiredFeatures.end(), ","); 773 SR.RequiredExtensions = RFs; 774 SR.NF = NF; 775 SR.HasMasked = HasMasked; 776 SR.HasVL = HasVL; 777 SR.HasMaskedOffOperand = HasMaskedOffOperand; 778 SR.HasTailPolicy = HasTailPolicy; 779 SR.HasMaskPolicy = HasMaskPolicy; 780 SR.UnMaskedPolicyScheme = static_cast<uint8_t>(UnMaskedPolicyScheme); 781 SR.MaskedPolicyScheme = static_cast<uint8_t>(MaskedPolicyScheme); 782 SR.Prototype = std::move(BasicPrototype); 783 SR.Suffix = parsePrototypes(SuffixProto); 784 SR.OverloadedSuffix = parsePrototypes(OverloadedSuffixProto); 785 SR.IsTuple = IsTuple; 786 SR.HasFRMRoundModeOp = HasFRMRoundModeOp; 787 788 SemaRecords->push_back(SR); 789 } 790 } 791 792 void RVVEmitter::printHeaderCode(raw_ostream &OS) { 793 for (const Record *R : Records.getAllDerivedDefinitions("RVVHeader")) { 794 StringRef HeaderCodeStr = R->getValueAsString("HeaderCode"); 795 OS << HeaderCodeStr.str(); 796 } 797 } 798 799 void RVVEmitter::createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out, 800 SemaSignatureTable &SST, 801 ArrayRef<SemaRecord> SemaRecords) { 802 SST.init(SemaRecords); 803 804 for (const auto &SR : SemaRecords) { 805 Out.emplace_back(RVVIntrinsicRecord()); 806 RVVIntrinsicRecord &R = Out.back(); 807 R.Name = SR.Name.c_str(); 808 R.OverloadedName = SR.OverloadedName.c_str(); 809 R.PrototypeIndex = SST.getIndex(SR.Prototype); 810 R.SuffixIndex = SST.getIndex(SR.Suffix); 811 R.OverloadedSuffixIndex = SST.getIndex(SR.OverloadedSuffix); 812 R.PrototypeLength = SR.Prototype.size(); 813 R.SuffixLength = SR.Suffix.size(); 814 R.OverloadedSuffixSize = SR.OverloadedSuffix.size(); 815 R.RequiredExtensions = SR.RequiredExtensions.c_str(); 816 R.TypeRangeMask = SR.TypeRangeMask; 817 R.Log2LMULMask = SR.Log2LMULMask; 818 R.NF = SR.NF; 819 R.HasMasked = SR.HasMasked; 820 R.HasVL = SR.HasVL; 821 R.HasMaskedOffOperand = SR.HasMaskedOffOperand; 822 R.HasTailPolicy = SR.HasTailPolicy; 823 R.HasMaskPolicy = SR.HasMaskPolicy; 824 R.UnMaskedPolicyScheme = SR.UnMaskedPolicyScheme; 825 R.MaskedPolicyScheme = SR.MaskedPolicyScheme; 826 R.IsTuple = SR.IsTuple; 827 R.HasFRMRoundModeOp = SR.HasFRMRoundModeOp; 828 829 assert(R.PrototypeIndex != 830 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 831 assert(R.SuffixIndex != 832 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 833 assert(R.OverloadedSuffixIndex != 834 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX)); 835 } 836 } 837 838 void RVVEmitter::createSema(raw_ostream &OS) { 839 std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 840 std::vector<RVVIntrinsicRecord> RVVIntrinsicRecords; 841 SemaSignatureTable SST; 842 std::vector<SemaRecord> SemaRecords; 843 844 createRVVIntrinsics(Defs, &SemaRecords); 845 846 createRVVIntrinsicRecords(RVVIntrinsicRecords, SST, SemaRecords); 847 848 // Emit signature table for SemaRISCVVectorLookup.cpp. 849 OS << "#ifdef DECL_SIGNATURE_TABLE\n"; 850 SST.print(OS); 851 OS << "#endif\n"; 852 853 // Emit RVVIntrinsicRecords for SemaRISCVVectorLookup.cpp. 854 OS << "#ifdef DECL_INTRINSIC_RECORDS\n"; 855 for (const RVVIntrinsicRecord &Record : RVVIntrinsicRecords) 856 OS << Record; 857 OS << "#endif\n"; 858 } 859 860 namespace clang { 861 void EmitRVVHeader(const RecordKeeper &Records, raw_ostream &OS) { 862 RVVEmitter(Records).createHeader(OS); 863 } 864 865 void EmitRVVBuiltins(const RecordKeeper &Records, raw_ostream &OS) { 866 RVVEmitter(Records).createBuiltins(OS); 867 } 868 869 void EmitRVVBuiltinCG(const RecordKeeper &Records, raw_ostream &OS) { 870 RVVEmitter(Records).createCodeGen(OS); 871 } 872 873 void EmitRVVBuiltinSema(const RecordKeeper &Records, raw_ostream &OS) { 874 RVVEmitter(Records).createSema(OS); 875 } 876 877 } // End namespace clang 878