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