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