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/Twine.h" 24 #include "llvm/TableGen/Error.h" 25 #include "llvm/TableGen/Record.h" 26 #include <numeric> 27 28 using namespace llvm; 29 using namespace clang::RISCV; 30 31 namespace { 32 class RVVEmitter { 33 private: 34 RecordKeeper &Records; 35 // Concat BasicType, LMUL and Proto as key 36 StringMap<RVVType> LegalTypes; 37 StringSet<> IllegalTypes; 38 39 public: 40 RVVEmitter(RecordKeeper &R) : Records(R) {} 41 42 /// Emit riscv_vector.h 43 void createHeader(raw_ostream &o); 44 45 /// Emit all the __builtin prototypes and code needed by Sema. 46 void createBuiltins(raw_ostream &o); 47 48 /// Emit all the information needed to map builtin -> LLVM IR intrinsic. 49 void createCodeGen(raw_ostream &o); 50 51 std::string getSuffixStr(char Type, int Log2LMUL, StringRef Prototypes); 52 53 private: 54 /// Create all intrinsics and add them to \p Out 55 void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out); 56 /// Print HeaderCode in RVVHeader Record to \p Out 57 void printHeaderCode(raw_ostream &OS); 58 /// Compute output and input types by applying different config (basic type 59 /// and LMUL with type transformers). It also record result of type in legal 60 /// or illegal set to avoid compute the same config again. The result maybe 61 /// have illegal RVVType. 62 Optional<RVVTypes> computeTypes(BasicType BT, int Log2LMUL, unsigned NF, 63 ArrayRef<std::string> PrototypeSeq); 64 Optional<RVVTypePtr> computeType(BasicType BT, int Log2LMUL, StringRef Proto); 65 66 /// Emit Acrh predecessor definitions and body, assume the element of Defs are 67 /// sorted by extension. 68 void emitArchMacroAndBody( 69 std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &o, 70 std::function<void(raw_ostream &, const RVVIntrinsic &)>); 71 72 // Emit the architecture preprocessor definitions. Return true when emits 73 // non-empty string. 74 bool emitMacroRestrictionStr(RISCVPredefinedMacroT PredefinedMacros, 75 raw_ostream &o); 76 // Slice Prototypes string into sub prototype string and process each sub 77 // prototype string individually in the Handler. 78 void parsePrototypes(StringRef Prototypes, 79 std::function<void(StringRef)> Handler); 80 }; 81 82 } // namespace 83 84 void emitCodeGenSwitchBody(const RVVIntrinsic *RVVI, raw_ostream &OS) { 85 if (!RVVI->getIRName().empty()) 86 OS << " ID = Intrinsic::riscv_" + RVVI->getIRName() + ";\n"; 87 if (RVVI->getNF() >= 2) 88 OS << " NF = " + utostr(RVVI->getNF()) + ";\n"; 89 if (RVVI->hasManualCodegen()) { 90 OS << RVVI->getManualCodegen(); 91 OS << "break;\n"; 92 return; 93 } 94 95 if (RVVI->isMasked()) { 96 if (RVVI->hasVL()) { 97 OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n"; 98 if (RVVI->hasPolicyOperand()) 99 OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType()," 100 " TAIL_UNDISTURBED));\n"; 101 } else { 102 OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n"; 103 } 104 } else { 105 if (RVVI->hasPolicyOperand()) 106 OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(), " 107 "TAIL_UNDISTURBED));\n"; 108 else if (RVVI->hasPassthruOperand()) { 109 OS << " Ops.push_back(llvm::UndefValue::get(ResultType));\n"; 110 OS << " std::rotate(Ops.rbegin(), Ops.rbegin() + 1, Ops.rend());\n"; 111 } 112 } 113 114 OS << " IntrinsicTypes = {"; 115 ListSeparator LS; 116 for (const auto &Idx : RVVI->getIntrinsicTypes()) { 117 if (Idx == -1) 118 OS << LS << "ResultType"; 119 else 120 OS << LS << "Ops[" << Idx << "]->getType()"; 121 } 122 123 // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is 124 // always last operand. 125 if (RVVI->hasVL()) 126 OS << ", Ops.back()->getType()"; 127 OS << "};\n"; 128 OS << " break;\n"; 129 } 130 131 void emitIntrinsicFuncDef(const RVVIntrinsic &RVVI, raw_ostream &OS) { 132 OS << "__attribute__((__clang_builtin_alias__("; 133 OS << "__builtin_rvv_" << RVVI.getBuiltinName() << ")))\n"; 134 OS << RVVI.getOutputType()->getTypeStr() << " " << RVVI.getName() << "("; 135 // Emit function arguments 136 const RVVTypes &InputTypes = RVVI.getInputTypes(); 137 if (!InputTypes.empty()) { 138 ListSeparator LS; 139 for (unsigned i = 0; i < InputTypes.size(); ++i) 140 OS << LS << InputTypes[i]->getTypeStr(); 141 } 142 OS << ");\n"; 143 } 144 145 void emitMangledFuncDef(const RVVIntrinsic &RVVI, raw_ostream &OS) { 146 OS << "__attribute__((__clang_builtin_alias__("; 147 OS << "__builtin_rvv_" << RVVI.getBuiltinName() << ")))\n"; 148 OS << RVVI.getOutputType()->getTypeStr() << " " << RVVI.getMangledName() 149 << "("; 150 // Emit function arguments 151 const RVVTypes &InputTypes = RVVI.getInputTypes(); 152 if (!InputTypes.empty()) { 153 ListSeparator LS; 154 for (unsigned i = 0; i < InputTypes.size(); ++i) 155 OS << LS << InputTypes[i]->getTypeStr(); 156 } 157 OS << ");\n"; 158 } 159 160 //===----------------------------------------------------------------------===// 161 // RVVEmitter implementation 162 //===----------------------------------------------------------------------===// 163 void RVVEmitter::createHeader(raw_ostream &OS) { 164 165 OS << "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics " 166 "-------------------===\n" 167 " *\n" 168 " *\n" 169 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " 170 "Exceptions.\n" 171 " * See https://llvm.org/LICENSE.txt for license information.\n" 172 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 173 " *\n" 174 " *===-----------------------------------------------------------------" 175 "------===\n" 176 " */\n\n"; 177 178 OS << "#ifndef __RISCV_VECTOR_H\n"; 179 OS << "#define __RISCV_VECTOR_H\n\n"; 180 181 OS << "#include <stdint.h>\n"; 182 OS << "#include <stddef.h>\n\n"; 183 184 OS << "#ifndef __riscv_vector\n"; 185 OS << "#error \"Vector intrinsics require the vector extension.\"\n"; 186 OS << "#endif\n\n"; 187 188 OS << "#ifdef __cplusplus\n"; 189 OS << "extern \"C\" {\n"; 190 OS << "#endif\n\n"; 191 192 printHeaderCode(OS); 193 194 std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 195 createRVVIntrinsics(Defs); 196 197 auto printType = [&](auto T) { 198 OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr() 199 << ";\n"; 200 }; 201 202 constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3}; 203 // Print RVV boolean types. 204 for (int Log2LMUL : Log2LMULs) { 205 auto T = computeType('c', Log2LMUL, "m"); 206 if (T.hasValue()) 207 printType(T.getValue()); 208 } 209 // Print RVV int/float types. 210 for (char I : StringRef("csil")) { 211 for (int Log2LMUL : Log2LMULs) { 212 auto T = computeType(I, Log2LMUL, "v"); 213 if (T.hasValue()) { 214 printType(T.getValue()); 215 auto UT = computeType(I, Log2LMUL, "Uv"); 216 printType(UT.getValue()); 217 } 218 } 219 } 220 OS << "#if defined(__riscv_zvfh)\n"; 221 for (int Log2LMUL : Log2LMULs) { 222 auto T = computeType('x', Log2LMUL, "v"); 223 if (T.hasValue()) 224 printType(T.getValue()); 225 } 226 OS << "#endif\n"; 227 228 OS << "#if defined(__riscv_f)\n"; 229 for (int Log2LMUL : Log2LMULs) { 230 auto T = computeType('f', Log2LMUL, "v"); 231 if (T.hasValue()) 232 printType(T.getValue()); 233 } 234 OS << "#endif\n"; 235 236 OS << "#if defined(__riscv_d)\n"; 237 for (int Log2LMUL : Log2LMULs) { 238 auto T = computeType('d', Log2LMUL, "v"); 239 if (T.hasValue()) 240 printType(T.getValue()); 241 } 242 OS << "#endif\n\n"; 243 244 // The same extension include in the same arch guard marco. 245 llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A, 246 const std::unique_ptr<RVVIntrinsic> &B) { 247 return A->getRISCVPredefinedMacros() < B->getRISCVPredefinedMacros(); 248 }); 249 250 OS << "#define __rvv_ai static __inline__\n"; 251 252 // Print intrinsic functions with macro 253 emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) { 254 OS << "__rvv_ai "; 255 emitIntrinsicFuncDef(Inst, OS); 256 }); 257 258 OS << "#undef __rvv_ai\n\n"; 259 260 OS << "#define __riscv_v_intrinsic_overloading 1\n"; 261 262 // Print Overloaded APIs 263 OS << "#define __rvv_aio static __inline__ " 264 "__attribute__((__overloadable__))\n"; 265 266 emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) { 267 if (!Inst.isMasked() && !Inst.hasUnMaskedOverloaded()) 268 return; 269 OS << "__rvv_aio "; 270 emitMangledFuncDef(Inst, OS); 271 }); 272 273 OS << "#undef __rvv_aio\n"; 274 275 OS << "\n#ifdef __cplusplus\n"; 276 OS << "}\n"; 277 OS << "#endif // __cplusplus\n"; 278 OS << "#endif // __RISCV_VECTOR_H\n"; 279 } 280 281 void RVVEmitter::createBuiltins(raw_ostream &OS) { 282 std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 283 createRVVIntrinsics(Defs); 284 285 // Map to keep track of which builtin names have already been emitted. 286 StringMap<RVVIntrinsic *> BuiltinMap; 287 288 OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n"; 289 OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, " 290 "ATTRS, \"zve32x\")\n"; 291 OS << "#endif\n"; 292 for (auto &Def : Defs) { 293 auto P = 294 BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); 295 if (!P.second) { 296 // Verf that this would have produced the same builtin definition. 297 if (P.first->second->hasBuiltinAlias() != Def->hasBuiltinAlias()) 298 PrintFatalError("Builtin with same name has different hasAutoDef"); 299 else if (!Def->hasBuiltinAlias() && 300 P.first->second->getBuiltinTypeStr() != Def->getBuiltinTypeStr()) 301 PrintFatalError("Builtin with same name has different type string"); 302 continue; 303 } 304 OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getBuiltinName() << ",\""; 305 if (!Def->hasBuiltinAlias()) 306 OS << Def->getBuiltinTypeStr(); 307 OS << "\", \"n\")\n"; 308 } 309 OS << "#undef RISCVV_BUILTIN\n"; 310 } 311 312 void RVVEmitter::createCodeGen(raw_ostream &OS) { 313 std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 314 createRVVIntrinsics(Defs); 315 // IR name could be empty, use the stable sort preserves the relative order. 316 llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A, 317 const std::unique_ptr<RVVIntrinsic> &B) { 318 return A->getIRName() < B->getIRName(); 319 }); 320 321 // Map to keep track of which builtin names have already been emitted. 322 StringMap<RVVIntrinsic *> BuiltinMap; 323 324 // Print switch body when the ir name or ManualCodegen changes from previous 325 // iteration. 326 RVVIntrinsic *PrevDef = Defs.begin()->get(); 327 for (auto &Def : Defs) { 328 StringRef CurIRName = Def->getIRName(); 329 if (CurIRName != PrevDef->getIRName() || 330 (Def->getManualCodegen() != PrevDef->getManualCodegen())) { 331 emitCodeGenSwitchBody(PrevDef, OS); 332 } 333 PrevDef = Def.get(); 334 335 auto P = 336 BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); 337 if (P.second) { 338 OS << "case RISCVVector::BI__builtin_rvv_" << Def->getBuiltinName() 339 << ":\n"; 340 continue; 341 } 342 343 if (P.first->second->getIRName() != Def->getIRName()) 344 PrintFatalError("Builtin with same name has different IRName"); 345 else if (P.first->second->getManualCodegen() != Def->getManualCodegen()) 346 PrintFatalError("Builtin with same name has different ManualCodegen"); 347 else if (P.first->second->getNF() != Def->getNF()) 348 PrintFatalError("Builtin with same name has different NF"); 349 else if (P.first->second->isMasked() != Def->isMasked()) 350 PrintFatalError("Builtin with same name has different isMasked"); 351 else if (P.first->second->hasVL() != Def->hasVL()) 352 PrintFatalError("Builtin with same name has different hasVL"); 353 else if (P.first->second->getPolicyScheme() != Def->getPolicyScheme()) 354 PrintFatalError("Builtin with same name has different getPolicyScheme"); 355 else if (P.first->second->getIntrinsicTypes() != Def->getIntrinsicTypes()) 356 PrintFatalError("Builtin with same name has different IntrinsicTypes"); 357 } 358 emitCodeGenSwitchBody(Defs.back().get(), OS); 359 OS << "\n"; 360 } 361 362 void RVVEmitter::parsePrototypes(StringRef Prototypes, 363 std::function<void(StringRef)> Handler) { 364 const StringRef Primaries("evwqom0ztul"); 365 while (!Prototypes.empty()) { 366 size_t Idx = 0; 367 // Skip over complex prototype because it could contain primitive type 368 // character. 369 if (Prototypes[0] == '(') 370 Idx = Prototypes.find_first_of(')'); 371 Idx = Prototypes.find_first_of(Primaries, Idx); 372 assert(Idx != StringRef::npos); 373 Handler(Prototypes.slice(0, Idx + 1)); 374 Prototypes = Prototypes.drop_front(Idx + 1); 375 } 376 } 377 378 std::string RVVEmitter::getSuffixStr(char Type, int Log2LMUL, 379 StringRef Prototypes) { 380 SmallVector<std::string> SuffixStrs; 381 parsePrototypes(Prototypes, [&](StringRef Proto) { 382 auto T = computeType(Type, Log2LMUL, Proto); 383 SuffixStrs.push_back(T.getValue()->getShortStr()); 384 }); 385 return join(SuffixStrs, "_"); 386 } 387 388 void RVVEmitter::createRVVIntrinsics( 389 std::vector<std::unique_ptr<RVVIntrinsic>> &Out) { 390 std::vector<Record *> RV = Records.getAllDerivedDefinitions("RVVBuiltin"); 391 for (auto *R : RV) { 392 StringRef Name = R->getValueAsString("Name"); 393 StringRef SuffixProto = R->getValueAsString("Suffix"); 394 StringRef MangledName = R->getValueAsString("MangledName"); 395 StringRef MangledSuffixProto = R->getValueAsString("MangledSuffix"); 396 StringRef Prototypes = R->getValueAsString("Prototype"); 397 StringRef TypeRange = R->getValueAsString("TypeRange"); 398 bool HasMasked = R->getValueAsBit("HasMasked"); 399 bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand"); 400 bool HasVL = R->getValueAsBit("HasVL"); 401 Record *MaskedPolicyRecord = R->getValueAsDef("MaskedPolicy"); 402 PolicyScheme MaskedPolicy = 403 static_cast<PolicyScheme>(MaskedPolicyRecord->getValueAsInt("Value")); 404 Record *UnMaskedPolicyRecord = R->getValueAsDef("UnMaskedPolicy"); 405 PolicyScheme UnMaskedPolicy = 406 static_cast<PolicyScheme>(UnMaskedPolicyRecord->getValueAsInt("Value")); 407 bool HasUnMaskedOverloaded = R->getValueAsBit("HasUnMaskedOverloaded"); 408 std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL"); 409 bool HasBuiltinAlias = R->getValueAsBit("HasBuiltinAlias"); 410 StringRef ManualCodegen = R->getValueAsString("ManualCodegen"); 411 StringRef MaskedManualCodegen = R->getValueAsString("MaskedManualCodegen"); 412 std::vector<int64_t> IntrinsicTypes = 413 R->getValueAsListOfInts("IntrinsicTypes"); 414 std::vector<StringRef> RequiredFeatures = 415 R->getValueAsListOfStrings("RequiredFeatures"); 416 StringRef IRName = R->getValueAsString("IRName"); 417 StringRef MaskedIRName = R->getValueAsString("MaskedIRName"); 418 unsigned NF = R->getValueAsInt("NF"); 419 420 // Parse prototype and create a list of primitive type with transformers 421 // (operand) in ProtoSeq. ProtoSeq[0] is output operand. 422 SmallVector<std::string> ProtoSeq; 423 parsePrototypes(Prototypes, [&ProtoSeq](StringRef Proto) { 424 ProtoSeq.push_back(Proto.str()); 425 }); 426 427 // Compute Builtin types 428 SmallVector<std::string> ProtoMaskSeq = ProtoSeq; 429 if (HasMasked) { 430 // If HasMaskedOffOperand, insert result type as first input operand. 431 if (HasMaskedOffOperand) { 432 if (NF == 1) { 433 ProtoMaskSeq.insert(ProtoMaskSeq.begin() + 1, ProtoSeq[0]); 434 } else { 435 // Convert 436 // (void, op0 address, op1 address, ...) 437 // to 438 // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...) 439 for (unsigned I = 0; I < NF; ++I) 440 ProtoMaskSeq.insert( 441 ProtoMaskSeq.begin() + NF + 1, 442 ProtoSeq[1].substr(1)); // Use substr(1) to skip '*' 443 } 444 } 445 if (HasMaskedOffOperand && NF > 1) { 446 // Convert 447 // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...) 448 // to 449 // (void, op0 address, op1 address, ..., mask, maskedoff0, maskedoff1, 450 // ...) 451 ProtoMaskSeq.insert(ProtoMaskSeq.begin() + NF + 1, "m"); 452 } else { 453 // If HasMasked, insert 'm' as first input operand. 454 ProtoMaskSeq.insert(ProtoMaskSeq.begin() + 1, "m"); 455 } 456 } 457 // If HasVL, append 'z' to last operand 458 if (HasVL) { 459 ProtoSeq.push_back("z"); 460 ProtoMaskSeq.push_back("z"); 461 } 462 463 // Create Intrinsics for each type and LMUL. 464 for (char I : TypeRange) { 465 for (int Log2LMUL : Log2LMULList) { 466 Optional<RVVTypes> Types = computeTypes(I, Log2LMUL, NF, ProtoSeq); 467 // Ignored to create new intrinsic if there are any illegal types. 468 if (!Types.hasValue()) 469 continue; 470 471 auto SuffixStr = getSuffixStr(I, Log2LMUL, SuffixProto); 472 auto MangledSuffixStr = getSuffixStr(I, Log2LMUL, MangledSuffixProto); 473 // Create a unmasked intrinsic 474 Out.push_back(std::make_unique<RVVIntrinsic>( 475 Name, SuffixStr, MangledName, MangledSuffixStr, IRName, 476 /*IsMasked=*/false, /*HasMaskedOffOperand=*/false, HasVL, 477 UnMaskedPolicy, HasUnMaskedOverloaded, HasBuiltinAlias, 478 ManualCodegen, Types.getValue(), IntrinsicTypes, RequiredFeatures, 479 NF)); 480 if (HasMasked) { 481 // Create a masked intrinsic 482 Optional<RVVTypes> MaskTypes = 483 computeTypes(I, Log2LMUL, NF, ProtoMaskSeq); 484 Out.push_back(std::make_unique<RVVIntrinsic>( 485 Name, SuffixStr, MangledName, MangledSuffixStr, MaskedIRName, 486 /*IsMasked=*/true, HasMaskedOffOperand, HasVL, MaskedPolicy, 487 HasUnMaskedOverloaded, HasBuiltinAlias, MaskedManualCodegen, 488 MaskTypes.getValue(), IntrinsicTypes, RequiredFeatures, NF)); 489 } 490 } // end for Log2LMULList 491 } // end for TypeRange 492 } 493 } 494 495 void RVVEmitter::printHeaderCode(raw_ostream &OS) { 496 std::vector<Record *> RVVHeaders = 497 Records.getAllDerivedDefinitions("RVVHeader"); 498 for (auto *R : RVVHeaders) { 499 StringRef HeaderCodeStr = R->getValueAsString("HeaderCode"); 500 OS << HeaderCodeStr.str(); 501 } 502 } 503 504 Optional<RVVTypes> 505 RVVEmitter::computeTypes(BasicType BT, int Log2LMUL, unsigned NF, 506 ArrayRef<std::string> PrototypeSeq) { 507 // LMUL x NF must be less than or equal to 8. 508 if ((Log2LMUL >= 1) && (1 << Log2LMUL) * NF > 8) 509 return llvm::None; 510 511 RVVTypes Types; 512 for (const std::string &Proto : PrototypeSeq) { 513 auto T = computeType(BT, Log2LMUL, Proto); 514 if (!T.hasValue()) 515 return llvm::None; 516 // Record legal type index 517 Types.push_back(T.getValue()); 518 } 519 return Types; 520 } 521 522 Optional<RVVTypePtr> RVVEmitter::computeType(BasicType BT, int Log2LMUL, 523 StringRef Proto) { 524 std::string Idx = Twine(Twine(BT) + Twine(Log2LMUL) + Proto).str(); 525 // Search first 526 auto It = LegalTypes.find(Idx); 527 if (It != LegalTypes.end()) 528 return &(It->second); 529 if (IllegalTypes.count(Idx)) 530 return llvm::None; 531 // Compute type and record the result. 532 RVVType T(BT, Log2LMUL, Proto); 533 if (T.isValid()) { 534 // Record legal type index and value. 535 LegalTypes.insert({Idx, T}); 536 return &(LegalTypes[Idx]); 537 } 538 // Record illegal type index. 539 IllegalTypes.insert(Idx); 540 return llvm::None; 541 } 542 543 void RVVEmitter::emitArchMacroAndBody( 544 std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &OS, 545 std::function<void(raw_ostream &, const RVVIntrinsic &)> PrintBody) { 546 RISCVPredefinedMacroT PrevMacros = 547 (*Defs.begin())->getRISCVPredefinedMacros(); 548 bool NeedEndif = emitMacroRestrictionStr(PrevMacros, OS); 549 for (auto &Def : Defs) { 550 RISCVPredefinedMacroT CurMacros = Def->getRISCVPredefinedMacros(); 551 if (CurMacros != PrevMacros) { 552 if (NeedEndif) 553 OS << "#endif\n\n"; 554 NeedEndif = emitMacroRestrictionStr(CurMacros, OS); 555 PrevMacros = CurMacros; 556 } 557 if (Def->hasBuiltinAlias()) 558 PrintBody(OS, *Def); 559 } 560 if (NeedEndif) 561 OS << "#endif\n\n"; 562 } 563 564 bool RVVEmitter::emitMacroRestrictionStr(RISCVPredefinedMacroT PredefinedMacros, 565 raw_ostream &OS) { 566 if (PredefinedMacros == RISCVPredefinedMacro::Basic) 567 return false; 568 OS << "#if "; 569 ListSeparator LS(" && "); 570 if (PredefinedMacros & RISCVPredefinedMacro::V) 571 OS << LS << "defined(__riscv_v)"; 572 if (PredefinedMacros & RISCVPredefinedMacro::Zvfh) 573 OS << LS << "defined(__riscv_zvfh)"; 574 if (PredefinedMacros & RISCVPredefinedMacro::RV64) 575 OS << LS << "(__riscv_xlen == 64)"; 576 if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELen64) 577 OS << LS << "(__riscv_v_elen >= 64)"; 578 if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELenFp32) 579 OS << LS << "(__riscv_v_elen_fp >= 32)"; 580 if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELenFp64) 581 OS << LS << "(__riscv_v_elen_fp >= 64)"; 582 OS << "\n"; 583 return true; 584 } 585 586 namespace clang { 587 void EmitRVVHeader(RecordKeeper &Records, raw_ostream &OS) { 588 RVVEmitter(Records).createHeader(OS); 589 } 590 591 void EmitRVVBuiltins(RecordKeeper &Records, raw_ostream &OS) { 592 RVVEmitter(Records).createBuiltins(OS); 593 } 594 595 void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 596 RVVEmitter(Records).createCodeGen(OS); 597 } 598 599 } // End namespace clang 600