[NFC][Coroutines] Use structured binding with llvm::enumerate in CoroSplit (#116879)
[llvm-project.git] / clang / utils / TableGen / RISCVVEmitter.cpp
blob68d7831c117458d733242c17bef421d3abbc5f9c
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.
13 // See also the documentation in include/clang/Basic/riscv_vector.td.
15 //===----------------------------------------------------------------------===//
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>
27 using namespace llvm;
28 using namespace clang::RISCV;
30 namespace {
31 struct SemaRecord {
32 // Intrinsic name, e.g. vadd_vv
33 std::string Name;
35 // Overloaded intrinsic name, could be empty if can be computed from Name
36 // e.g. vadd
37 std::string OverloadedName;
39 // Supported type, mask of BasicType.
40 unsigned TypeRangeMask;
42 // Supported LMUL.
43 unsigned Log2LMULMask;
45 // Required extensions for this intrinsic.
46 uint32_t RequiredExtensions;
48 // Prototype for this intrinsic.
49 SmallVector<PrototypeDescriptor> Prototype;
51 // Suffix of intrinsic name.
52 SmallVector<PrototypeDescriptor> Suffix;
54 // Suffix of overloaded intrinsic name.
55 SmallVector<PrototypeDescriptor> OverloadedSuffix;
57 // Number of field, large than 1 if it's segment load/store.
58 unsigned NF;
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;
73 // Compressed function signature table.
74 class SemaSignatureTable {
75 private:
76 std::vector<PrototypeDescriptor> SignatureTable;
78 void insert(ArrayRef<PrototypeDescriptor> Signature);
80 public:
81 static constexpr unsigned INVALID_INDEX = ~0U;
83 // Create compressed signature table from SemaRecords.
84 void init(ArrayRef<SemaRecord> SemaRecords);
86 // Query the Signature, return INVALID_INDEX if not found.
87 unsigned getIndex(ArrayRef<PrototypeDescriptor> Signature);
89 /// Print signature table in RVVHeader Record to \p OS
90 void print(raw_ostream &OS);
93 class RVVEmitter {
94 private:
95 const RecordKeeper &Records;
96 RVVTypeCache TypeCache;
98 public:
99 RVVEmitter(const RecordKeeper &R) : Records(R) {}
101 /// Emit riscv_vector.h
102 void createHeader(raw_ostream &o);
104 /// Emit all the __builtin prototypes and code needed by Sema.
105 void createBuiltins(raw_ostream &o);
107 /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
108 void createCodeGen(raw_ostream &o);
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);
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);
124 /// Print HeaderCode in RVVHeader Record to \p Out
125 void printHeaderCode(raw_ostream &OS);
128 } // namespace
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;
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));
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;
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;
181 if (IRName.starts_with("vsoxseg") || IRName.starts_with("vsuxseg"))
182 return RVVI->isMasked() ? 1 : 0;
184 return (unsigned)-1;
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;
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)
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)
214 #define KEY_VAL_ALL_NF(NAME, SEW, LOG2SEW) \
215 KEY_VAL_ALL_NF_BASE(KEY_VAL_ALL_W_POLICY, NAME, SEW, LOG2SEW,)
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)
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)
226 #define KEY_VAL_ALL_NF_SEW(NAME) \
227 KEY_VAL_ALL_NF_SEW_BASE(KEY_VAL_ALL_NF, NAME)
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
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)};
238 #undef KEY_VAL_ALL_NF_SEW
239 #undef KEY_VAL_ALL_NF
240 #undef KEY_VAL
242 return SegInsts.lookup(InstName);
245 void emitCodeGenSwitchBody(const RVVIntrinsic *RVVI, raw_ostream &OS) {
246 if (!RVVI->getIRName().empty())
247 OS << " ID = Intrinsic::riscv_" + RVVI->getIRName() + ";\n";
249 OS << " PolicyAttrs = " << RVVI->getPolicyAttrsBits() << ";\n";
250 OS << " SegInstSEW = " << getSegInstLog2SEW(RVVI->getOverloadedName())
251 << ";\n";
253 if (RVVI->hasManualCodegen()) {
254 OS << "IsMasked = " << (RVVI->isMasked() ? "true" : "false") << ";\n";
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";
263 OS << RVVI->getManualCodegen();
264 OS << "break;\n";
265 return;
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.");
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";
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";
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()";
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";
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();
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];
336 return false;
340 std::set<SmallVector<PrototypeDescriptor>, Compare> Signatures;
341 auto InsertToSignatureSet =
342 [&](const SmallVector<PrototypeDescriptor> &Signature) {
343 if (Signature.empty())
344 return;
346 Signatures.insert(Signature);
349 assert(!SemaRecords.empty());
351 for (const SemaRecord &SR : SemaRecords) {
352 InsertToSignatureSet(SR.Prototype);
353 InsertToSignatureSet(SR.Suffix);
354 InsertToSignatureSet(SR.OverloadedSuffix);
357 for (auto &Sig : Signatures)
358 insert(Sig);
361 void SemaSignatureTable::insert(ArrayRef<PrototypeDescriptor> Signature) {
362 if (getIndex(Signature) != INVALID_INDEX)
363 return;
365 // Insert Signature into SignatureTable if not found in the table.
366 SignatureTable.insert(SignatureTable.begin(), Signature.begin(),
367 Signature.end());
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;
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;
386 return INVALID_INDEX;
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";
396 //===----------------------------------------------------------------------===//
397 // RVVEmitter implementation
398 //===----------------------------------------------------------------------===//
399 void RVVEmitter::createHeader(raw_ostream &OS) {
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";
414 OS << "#ifndef __RISCV_VECTOR_H\n";
415 OS << "#define __RISCV_VECTOR_H\n\n";
417 OS << "#include <stdint.h>\n";
418 OS << "#include <stddef.h>\n\n";
420 OS << "#ifdef __cplusplus\n";
421 OS << "extern \"C\" {\n";
422 OS << "#endif\n\n";
424 OS << "#pragma clang riscv intrinsic vector\n\n";
426 printHeaderCode(OS);
428 auto printType = [&](auto T) {
429 OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr()
430 << ";\n";
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);
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);
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);
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);
491 OS << "#define __riscv_v_intrinsic_overloading 1\n";
493 OS << "\n#ifdef __cplusplus\n";
494 OS << "}\n";
495 OS << "#endif // __cplusplus\n";
496 OS << "#endif // __RISCV_VECTOR_H\n";
499 void RVVEmitter::createBuiltins(raw_ostream &OS) {
500 std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
501 createRVVIntrinsics(Defs);
503 // Map to keep track of which builtin names have already been emitted.
504 StringMap<RVVIntrinsic *> BuiltinMap;
506 OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n";
507 OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, "
508 "ATTRS, \"zve32x\")\n";
509 OS << "#endif\n";
510 for (auto &Def : Defs) {
511 auto P =
512 BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get()));
513 if (!P.second) {
514 // Verf that this would have produced the same builtin definition.
515 if (P.first->second->hasBuiltinAlias() != Def->hasBuiltinAlias())
516 PrintFatalError("Builtin with same name has different hasAutoDef");
517 else if (!Def->hasBuiltinAlias() &&
518 P.first->second->getBuiltinTypeStr() != Def->getBuiltinTypeStr())
519 PrintFatalError("Builtin with same name has different type string");
520 continue;
522 OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getBuiltinName() << ",\"";
523 if (!Def->hasBuiltinAlias())
524 OS << Def->getBuiltinTypeStr();
525 OS << "\", \"n\")\n";
527 OS << "#undef RISCVV_BUILTIN\n";
530 void RVVEmitter::createCodeGen(raw_ostream &OS) {
531 std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
532 createRVVIntrinsics(Defs);
533 // IR name could be empty, use the stable sort preserves the relative order.
534 stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A,
535 const std::unique_ptr<RVVIntrinsic> &B) {
536 if (A->getIRName() == B->getIRName())
537 return (A->getPolicyAttrs() < B->getPolicyAttrs());
538 return (A->getIRName() < B->getIRName());
541 // Map to keep track of which builtin names have already been emitted.
542 StringMap<RVVIntrinsic *> BuiltinMap;
544 // Print switch body when the ir name, ManualCodegen, policy or log2sew
545 // changes from previous iteration.
546 RVVIntrinsic *PrevDef = Defs.begin()->get();
547 for (auto &Def : Defs) {
548 StringRef CurIRName = Def->getIRName();
549 if (CurIRName != PrevDef->getIRName() ||
550 (Def->getManualCodegen() != PrevDef->getManualCodegen()) ||
551 (Def->getPolicyAttrs() != PrevDef->getPolicyAttrs()) ||
552 (getSegInstLog2SEW(Def->getOverloadedName()) !=
553 getSegInstLog2SEW(PrevDef->getOverloadedName()))) {
554 emitCodeGenSwitchBody(PrevDef, OS);
556 PrevDef = Def.get();
558 auto P =
559 BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get()));
560 if (P.second) {
561 OS << "case RISCVVector::BI__builtin_rvv_" << Def->getBuiltinName()
562 << ":\n";
563 continue;
566 if (P.first->second->getIRName() != Def->getIRName())
567 PrintFatalError("Builtin with same name has different IRName");
568 else if (P.first->second->getManualCodegen() != Def->getManualCodegen())
569 PrintFatalError("Builtin with same name has different ManualCodegen");
570 else if (P.first->second->isMasked() != Def->isMasked())
571 PrintFatalError("Builtin with same name has different isMasked");
572 else if (P.first->second->hasVL() != Def->hasVL())
573 PrintFatalError("Builtin with same name has different hasVL");
574 else if (P.first->second->getPolicyScheme() != Def->getPolicyScheme())
575 PrintFatalError("Builtin with same name has different getPolicyScheme");
576 else if (P.first->second->getIntrinsicTypes() != Def->getIntrinsicTypes())
577 PrintFatalError("Builtin with same name has different IntrinsicTypes");
579 emitCodeGenSwitchBody(Defs.back().get(), OS);
580 OS << "\n";
583 void RVVEmitter::createRVVIntrinsics(
584 std::vector<std::unique_ptr<RVVIntrinsic>> &Out,
585 std::vector<SemaRecord> *SemaRecords) {
586 for (const Record *R : Records.getAllDerivedDefinitions("RVVBuiltin")) {
587 StringRef Name = R->getValueAsString("Name");
588 StringRef SuffixProto = R->getValueAsString("Suffix");
589 StringRef OverloadedName = R->getValueAsString("OverloadedName");
590 StringRef OverloadedSuffixProto = R->getValueAsString("OverloadedSuffix");
591 StringRef Prototypes = R->getValueAsString("Prototype");
592 StringRef TypeRange = R->getValueAsString("TypeRange");
593 bool HasMasked = R->getValueAsBit("HasMasked");
594 bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand");
595 bool HasVL = R->getValueAsBit("HasVL");
596 const Record *MPSRecord = R->getValueAsDef("MaskedPolicyScheme");
597 auto MaskedPolicyScheme =
598 static_cast<PolicyScheme>(MPSRecord->getValueAsInt("Value"));
599 const Record *UMPSRecord = R->getValueAsDef("UnMaskedPolicyScheme");
600 auto UnMaskedPolicyScheme =
601 static_cast<PolicyScheme>(UMPSRecord->getValueAsInt("Value"));
602 std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL");
603 bool HasTailPolicy = R->getValueAsBit("HasTailPolicy");
604 bool HasMaskPolicy = R->getValueAsBit("HasMaskPolicy");
605 bool SupportOverloading = R->getValueAsBit("SupportOverloading");
606 bool HasBuiltinAlias = R->getValueAsBit("HasBuiltinAlias");
607 StringRef ManualCodegen = R->getValueAsString("ManualCodegen");
608 std::vector<int64_t> IntrinsicTypes =
609 R->getValueAsListOfInts("IntrinsicTypes");
610 std::vector<StringRef> RequiredFeatures =
611 R->getValueAsListOfStrings("RequiredFeatures");
612 StringRef IRName = R->getValueAsString("IRName");
613 StringRef MaskedIRName = R->getValueAsString("MaskedIRName");
614 unsigned NF = R->getValueAsInt("NF");
615 bool IsTuple = R->getValueAsBit("IsTuple");
616 bool HasFRMRoundModeOp = R->getValueAsBit("HasFRMRoundModeOp");
618 const Policy DefaultPolicy;
619 SmallVector<Policy> SupportedUnMaskedPolicies =
620 RVVIntrinsic::getSupportedUnMaskedPolicies();
621 SmallVector<Policy> SupportedMaskedPolicies =
622 RVVIntrinsic::getSupportedMaskedPolicies(HasTailPolicy, HasMaskPolicy);
624 // Parse prototype and create a list of primitive type with transformers
625 // (operand) in Prototype. Prototype[0] is output operand.
626 SmallVector<PrototypeDescriptor> BasicPrototype =
627 parsePrototypes(Prototypes);
629 SmallVector<PrototypeDescriptor> SuffixDesc = parsePrototypes(SuffixProto);
630 SmallVector<PrototypeDescriptor> OverloadedSuffixDesc =
631 parsePrototypes(OverloadedSuffixProto);
633 // Compute Builtin types
634 auto Prototype = RVVIntrinsic::computeBuiltinTypes(
635 BasicPrototype, /*IsMasked=*/false,
636 /*HasMaskedOffOperand=*/false, HasVL, NF, UnMaskedPolicyScheme,
637 DefaultPolicy, IsTuple);
638 SmallVector<PrototypeDescriptor> MaskedPrototype;
639 if (HasMasked)
640 MaskedPrototype = RVVIntrinsic::computeBuiltinTypes(
641 BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, NF,
642 MaskedPolicyScheme, DefaultPolicy, IsTuple);
644 // Create Intrinsics for each type and LMUL.
645 for (char I : TypeRange) {
646 for (int Log2LMUL : Log2LMULList) {
647 BasicType BT = ParseBasicType(I);
648 std::optional<RVVTypes> Types =
649 TypeCache.computeTypes(BT, Log2LMUL, NF, Prototype);
650 // Ignored to create new intrinsic if there are any illegal types.
651 if (!Types)
652 continue;
654 auto SuffixStr =
655 RVVIntrinsic::getSuffixStr(TypeCache, BT, Log2LMUL, SuffixDesc);
656 auto OverloadedSuffixStr = RVVIntrinsic::getSuffixStr(
657 TypeCache, BT, Log2LMUL, OverloadedSuffixDesc);
658 // Create a unmasked intrinsic
659 Out.push_back(std::make_unique<RVVIntrinsic>(
660 Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName,
661 /*IsMasked=*/false, /*HasMaskedOffOperand=*/false, HasVL,
662 UnMaskedPolicyScheme, SupportOverloading, HasBuiltinAlias,
663 ManualCodegen, *Types, IntrinsicTypes, NF, DefaultPolicy,
664 HasFRMRoundModeOp));
665 if (UnMaskedPolicyScheme != PolicyScheme::SchemeNone)
666 for (auto P : SupportedUnMaskedPolicies) {
667 SmallVector<PrototypeDescriptor> PolicyPrototype =
668 RVVIntrinsic::computeBuiltinTypes(
669 BasicPrototype, /*IsMasked=*/false,
670 /*HasMaskedOffOperand=*/false, HasVL, NF,
671 UnMaskedPolicyScheme, P, IsTuple);
672 std::optional<RVVTypes> PolicyTypes =
673 TypeCache.computeTypes(BT, Log2LMUL, NF, PolicyPrototype);
674 Out.push_back(std::make_unique<RVVIntrinsic>(
675 Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName,
676 /*IsMask=*/false, /*HasMaskedOffOperand=*/false, HasVL,
677 UnMaskedPolicyScheme, SupportOverloading, HasBuiltinAlias,
678 ManualCodegen, *PolicyTypes, IntrinsicTypes, NF, P,
679 HasFRMRoundModeOp));
681 if (!HasMasked)
682 continue;
683 // Create a masked intrinsic
684 std::optional<RVVTypes> MaskTypes =
685 TypeCache.computeTypes(BT, Log2LMUL, NF, MaskedPrototype);
686 Out.push_back(std::make_unique<RVVIntrinsic>(
687 Name, SuffixStr, OverloadedName, OverloadedSuffixStr, MaskedIRName,
688 /*IsMasked=*/true, HasMaskedOffOperand, HasVL, MaskedPolicyScheme,
689 SupportOverloading, HasBuiltinAlias, ManualCodegen, *MaskTypes,
690 IntrinsicTypes, NF, DefaultPolicy, HasFRMRoundModeOp));
691 if (MaskedPolicyScheme == PolicyScheme::SchemeNone)
692 continue;
693 for (auto P : SupportedMaskedPolicies) {
694 SmallVector<PrototypeDescriptor> PolicyPrototype =
695 RVVIntrinsic::computeBuiltinTypes(
696 BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL,
697 NF, MaskedPolicyScheme, P, IsTuple);
698 std::optional<RVVTypes> PolicyTypes =
699 TypeCache.computeTypes(BT, Log2LMUL, NF, PolicyPrototype);
700 Out.push_back(std::make_unique<RVVIntrinsic>(
701 Name, SuffixStr, OverloadedName, OverloadedSuffixStr,
702 MaskedIRName, /*IsMasked=*/true, HasMaskedOffOperand, HasVL,
703 MaskedPolicyScheme, SupportOverloading, HasBuiltinAlias,
704 ManualCodegen, *PolicyTypes, IntrinsicTypes, NF, P,
705 HasFRMRoundModeOp));
707 } // End for Log2LMULList
708 } // End for TypeRange
710 // We don't emit vsetvli and vsetvlimax for SemaRecord.
711 // They are written in riscv_vector.td and will emit those marco define in
712 // riscv_vector.h
713 if (Name == "vsetvli" || Name == "vsetvlimax")
714 continue;
716 if (!SemaRecords)
717 continue;
719 // Create SemaRecord
720 SemaRecord SR;
721 SR.Name = Name.str();
722 SR.OverloadedName = OverloadedName.str();
723 BasicType TypeRangeMask = BasicType::Unknown;
724 for (char I : TypeRange)
725 TypeRangeMask |= ParseBasicType(I);
727 SR.TypeRangeMask = static_cast<unsigned>(TypeRangeMask);
729 unsigned Log2LMULMask = 0;
730 for (int Log2LMUL : Log2LMULList)
731 Log2LMULMask |= 1 << (Log2LMUL + 3);
733 SR.Log2LMULMask = Log2LMULMask;
735 SR.RequiredExtensions = 0;
736 for (auto RequiredFeature : RequiredFeatures) {
737 RVVRequire RequireExt =
738 StringSwitch<RVVRequire>(RequiredFeature)
739 .Case("RV64", RVV_REQ_RV64)
740 .Case("Zvfhmin", RVV_REQ_Zvfhmin)
741 .Case("Xsfvcp", RVV_REQ_Xsfvcp)
742 .Case("Xsfvfnrclipxfqf", RVV_REQ_Xsfvfnrclipxfqf)
743 .Case("Xsfvfwmaccqqq", RVV_REQ_Xsfvfwmaccqqq)
744 .Case("Xsfvqmaccdod", RVV_REQ_Xsfvqmaccdod)
745 .Case("Xsfvqmaccqoq", RVV_REQ_Xsfvqmaccqoq)
746 .Case("Zvbb", RVV_REQ_Zvbb)
747 .Case("Zvbc", RVV_REQ_Zvbc)
748 .Case("Zvkb", RVV_REQ_Zvkb)
749 .Case("Zvkg", RVV_REQ_Zvkg)
750 .Case("Zvkned", RVV_REQ_Zvkned)
751 .Case("Zvknha", RVV_REQ_Zvknha)
752 .Case("Zvknhb", RVV_REQ_Zvknhb)
753 .Case("Zvksed", RVV_REQ_Zvksed)
754 .Case("Zvksh", RVV_REQ_Zvksh)
755 .Case("Zvfbfwma", RVV_REQ_Zvfbfwma)
756 .Case("Zvfbfmin", RVV_REQ_Zvfbfmin)
757 .Case("Zvfh", RVV_REQ_Zvfh)
758 .Case("Experimental", RVV_REQ_Experimental)
759 .Default(RVV_REQ_None);
760 assert(RequireExt != RVV_REQ_None && "Unrecognized required feature?");
761 SR.RequiredExtensions |= RequireExt;
764 SR.NF = NF;
765 SR.HasMasked = HasMasked;
766 SR.HasVL = HasVL;
767 SR.HasMaskedOffOperand = HasMaskedOffOperand;
768 SR.HasTailPolicy = HasTailPolicy;
769 SR.HasMaskPolicy = HasMaskPolicy;
770 SR.UnMaskedPolicyScheme = static_cast<uint8_t>(UnMaskedPolicyScheme);
771 SR.MaskedPolicyScheme = static_cast<uint8_t>(MaskedPolicyScheme);
772 SR.Prototype = std::move(BasicPrototype);
773 SR.Suffix = parsePrototypes(SuffixProto);
774 SR.OverloadedSuffix = parsePrototypes(OverloadedSuffixProto);
775 SR.IsTuple = IsTuple;
776 SR.HasFRMRoundModeOp = HasFRMRoundModeOp;
778 SemaRecords->push_back(SR);
782 void RVVEmitter::printHeaderCode(raw_ostream &OS) {
783 for (const Record *R : Records.getAllDerivedDefinitions("RVVHeader")) {
784 StringRef HeaderCodeStr = R->getValueAsString("HeaderCode");
785 OS << HeaderCodeStr.str();
789 void RVVEmitter::createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out,
790 SemaSignatureTable &SST,
791 ArrayRef<SemaRecord> SemaRecords) {
792 SST.init(SemaRecords);
794 for (const auto &SR : SemaRecords) {
795 Out.emplace_back(RVVIntrinsicRecord());
796 RVVIntrinsicRecord &R = Out.back();
797 R.Name = SR.Name.c_str();
798 R.OverloadedName = SR.OverloadedName.c_str();
799 R.PrototypeIndex = SST.getIndex(SR.Prototype);
800 R.SuffixIndex = SST.getIndex(SR.Suffix);
801 R.OverloadedSuffixIndex = SST.getIndex(SR.OverloadedSuffix);
802 R.PrototypeLength = SR.Prototype.size();
803 R.SuffixLength = SR.Suffix.size();
804 R.OverloadedSuffixSize = SR.OverloadedSuffix.size();
805 R.RequiredExtensions = SR.RequiredExtensions;
806 R.TypeRangeMask = SR.TypeRangeMask;
807 R.Log2LMULMask = SR.Log2LMULMask;
808 R.NF = SR.NF;
809 R.HasMasked = SR.HasMasked;
810 R.HasVL = SR.HasVL;
811 R.HasMaskedOffOperand = SR.HasMaskedOffOperand;
812 R.HasTailPolicy = SR.HasTailPolicy;
813 R.HasMaskPolicy = SR.HasMaskPolicy;
814 R.UnMaskedPolicyScheme = SR.UnMaskedPolicyScheme;
815 R.MaskedPolicyScheme = SR.MaskedPolicyScheme;
816 R.IsTuple = SR.IsTuple;
817 R.HasFRMRoundModeOp = SR.HasFRMRoundModeOp;
819 assert(R.PrototypeIndex !=
820 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX));
821 assert(R.SuffixIndex !=
822 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX));
823 assert(R.OverloadedSuffixIndex !=
824 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX));
828 void RVVEmitter::createSema(raw_ostream &OS) {
829 std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
830 std::vector<RVVIntrinsicRecord> RVVIntrinsicRecords;
831 SemaSignatureTable SST;
832 std::vector<SemaRecord> SemaRecords;
834 createRVVIntrinsics(Defs, &SemaRecords);
836 createRVVIntrinsicRecords(RVVIntrinsicRecords, SST, SemaRecords);
838 // Emit signature table for SemaRISCVVectorLookup.cpp.
839 OS << "#ifdef DECL_SIGNATURE_TABLE\n";
840 SST.print(OS);
841 OS << "#endif\n";
843 // Emit RVVIntrinsicRecords for SemaRISCVVectorLookup.cpp.
844 OS << "#ifdef DECL_INTRINSIC_RECORDS\n";
845 for (const RVVIntrinsicRecord &Record : RVVIntrinsicRecords)
846 OS << Record;
847 OS << "#endif\n";
850 namespace clang {
851 void EmitRVVHeader(const RecordKeeper &Records, raw_ostream &OS) {
852 RVVEmitter(Records).createHeader(OS);
855 void EmitRVVBuiltins(const RecordKeeper &Records, raw_ostream &OS) {
856 RVVEmitter(Records).createBuiltins(OS);
859 void EmitRVVBuiltinCG(const RecordKeeper &Records, raw_ostream &OS) {
860 RVVEmitter(Records).createCodeGen(OS);
863 void EmitRVVBuiltinSema(const RecordKeeper &Records, raw_ostream &OS) {
864 RVVEmitter(Records).createSema(OS);
867 } // End namespace clang