[clang-format] Fix a bug in aligning comments above PPDirective (#72791)
[llvm-project.git] / clang / utils / TableGen / RISCVVEmitter.cpp
blobcf731e8414a3b832d99b768ac272d0486b03153f
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/SmallSet.h"
20 #include "llvm/ADT/StringExtras.h"
21 #include "llvm/ADT/StringMap.h"
22 #include "llvm/ADT/StringSet.h"
23 #include "llvm/ADT/StringSwitch.h"
24 #include "llvm/ADT/Twine.h"
25 #include "llvm/TableGen/Error.h"
26 #include "llvm/TableGen/Record.h"
27 #include <numeric>
28 #include <optional>
30 using namespace llvm;
31 using namespace clang::RISCV;
33 namespace {
34 struct SemaRecord {
35 // Intrinsic name, e.g. vadd_vv
36 std::string Name;
38 // Overloaded intrinsic name, could be empty if can be computed from Name
39 // e.g. vadd
40 std::string OverloadedName;
42 // Supported type, mask of BasicType.
43 unsigned TypeRangeMask;
45 // Supported LMUL.
46 unsigned Log2LMULMask;
48 // Required extensions for this intrinsic.
49 unsigned RequiredExtensions;
51 // Prototype for this intrinsic.
52 SmallVector<PrototypeDescriptor> Prototype;
54 // Suffix of intrinsic name.
55 SmallVector<PrototypeDescriptor> Suffix;
57 // Suffix of overloaded intrinsic name.
58 SmallVector<PrototypeDescriptor> OverloadedSuffix;
60 // Number of field, large than 1 if it's segment load/store.
61 unsigned NF;
63 bool HasMasked :1;
64 bool HasVL :1;
65 bool HasMaskedOffOperand :1;
66 bool HasTailPolicy : 1;
67 bool HasMaskPolicy : 1;
68 bool HasFRMRoundModeOp : 1;
69 bool IsTuple : 1;
70 uint8_t UnMaskedPolicyScheme : 2;
71 uint8_t MaskedPolicyScheme : 2;
74 // Compressed function signature table.
75 class SemaSignatureTable {
76 private:
77 std::vector<PrototypeDescriptor> SignatureTable;
79 void insert(ArrayRef<PrototypeDescriptor> Signature);
81 public:
82 static constexpr unsigned INVALID_INDEX = ~0U;
84 // Create compressed signature table from SemaRecords.
85 void init(ArrayRef<SemaRecord> SemaRecords);
87 // Query the Signature, return INVALID_INDEX if not found.
88 unsigned getIndex(ArrayRef<PrototypeDescriptor> Signature);
90 /// Print signature table in RVVHeader Record to \p OS
91 void print(raw_ostream &OS);
94 class RVVEmitter {
95 private:
96 RecordKeeper &Records;
97 RVVTypeCache TypeCache;
99 public:
100 RVVEmitter(RecordKeeper &R) : Records(R) {}
102 /// Emit riscv_vector.h
103 void createHeader(raw_ostream &o);
105 /// Emit all the __builtin prototypes and code needed by Sema.
106 void createBuiltins(raw_ostream &o);
108 /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
109 void createCodeGen(raw_ostream &o);
111 /// Emit all the information needed by SemaRISCVVectorLookup.cpp.
112 /// We've large number of intrinsic function for RVV, creating a customized
113 /// could speed up the compilation time.
114 void createSema(raw_ostream &o);
116 private:
117 /// Create all intrinsics and add them to \p Out and SemaRecords.
118 void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out,
119 std::vector<SemaRecord> *SemaRecords = nullptr);
120 /// Create all intrinsic records and SemaSignatureTable from SemaRecords.
121 void createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out,
122 SemaSignatureTable &SST,
123 ArrayRef<SemaRecord> SemaRecords);
125 /// Print HeaderCode in RVVHeader Record to \p Out
126 void printHeaderCode(raw_ostream &OS);
129 } // namespace
131 static BasicType ParseBasicType(char c) {
132 switch (c) {
133 case 'c':
134 return BasicType::Int8;
135 break;
136 case 's':
137 return BasicType::Int16;
138 break;
139 case 'i':
140 return BasicType::Int32;
141 break;
142 case 'l':
143 return BasicType::Int64;
144 break;
145 case 'x':
146 return BasicType::Float16;
147 break;
148 case 'f':
149 return BasicType::Float32;
150 break;
151 case 'd':
152 return BasicType::Float64;
153 break;
154 case 'b':
155 return BasicType::BFloat16;
156 break;
157 default:
158 return BasicType::Unknown;
162 static VectorTypeModifier getTupleVTM(unsigned NF) {
163 assert(2 <= NF && NF <= 8 && "2 <= NF <= 8");
164 return static_cast<VectorTypeModifier>(
165 static_cast<uint8_t>(VectorTypeModifier::Tuple2) + (NF - 2));
168 void emitCodeGenSwitchBody(const RVVIntrinsic *RVVI, raw_ostream &OS) {
169 if (!RVVI->getIRName().empty())
170 OS << " ID = Intrinsic::riscv_" + RVVI->getIRName() + ";\n";
171 if (RVVI->getNF() >= 2)
172 OS << " NF = " + utostr(RVVI->getNF()) + ";\n";
174 OS << " PolicyAttrs = " << RVVI->getPolicyAttrsBits() << ";\n";
176 if (RVVI->hasManualCodegen()) {
177 OS << "IsMasked = " << (RVVI->isMasked() ? "true" : "false") << ";\n";
178 OS << RVVI->getManualCodegen();
179 OS << "break;\n";
180 return;
183 // Cast pointer operand of vector load intrinsic.
184 for (const auto &I : enumerate(RVVI->getInputTypes())) {
185 if (I.value()->isPointer()) {
186 assert(RVVI->getIntrinsicTypes().front() == -1 &&
187 "RVVI should be vector load intrinsic.");
188 OS << " Ops[" << I.index() << "] = Builder.CreateBitCast(Ops[";
189 OS << I.index() << "], ResultType->getPointerTo());\n";
193 if (RVVI->isMasked()) {
194 if (RVVI->hasVL()) {
195 OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n";
196 if (RVVI->hasPolicyOperand())
197 OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(),"
198 " PolicyAttrs));\n";
199 if (RVVI->hasMaskedOffOperand() && RVVI->getPolicyAttrs().isTAMAPolicy())
200 OS << " Ops.insert(Ops.begin(), "
201 "llvm::PoisonValue::get(ResultType));\n";
202 // Masked reduction cases.
203 if (!RVVI->hasMaskedOffOperand() && RVVI->hasPassthruOperand() &&
204 RVVI->getPolicyAttrs().isTAMAPolicy())
205 OS << " Ops.insert(Ops.begin(), "
206 "llvm::PoisonValue::get(ResultType));\n";
207 } else {
208 OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n";
210 } else {
211 if (RVVI->hasPolicyOperand())
212 OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(), "
213 "PolicyAttrs));\n";
214 else if (RVVI->hasPassthruOperand() && RVVI->getPolicyAttrs().isTAPolicy())
215 OS << " Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));\n";
218 OS << " IntrinsicTypes = {";
219 ListSeparator LS;
220 for (const auto &Idx : RVVI->getIntrinsicTypes()) {
221 if (Idx == -1)
222 OS << LS << "ResultType";
223 else
224 OS << LS << "Ops[" << Idx << "]->getType()";
227 // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is
228 // always last operand.
229 if (RVVI->hasVL())
230 OS << ", Ops.back()->getType()";
231 OS << "};\n";
232 OS << " break;\n";
235 //===----------------------------------------------------------------------===//
236 // SemaSignatureTable implementation
237 //===----------------------------------------------------------------------===//
238 void SemaSignatureTable::init(ArrayRef<SemaRecord> SemaRecords) {
239 // Sort signature entries by length, let longer signature insert first, to
240 // make it more possible to reuse table entries, that can reduce ~10% table
241 // size.
242 struct Compare {
243 bool operator()(const SmallVector<PrototypeDescriptor> &A,
244 const SmallVector<PrototypeDescriptor> &B) const {
245 if (A.size() != B.size())
246 return A.size() > B.size();
248 size_t Len = A.size();
249 for (size_t i = 0; i < Len; ++i) {
250 if (A[i] != B[i])
251 return A[i] < B[i];
254 return false;
258 std::set<SmallVector<PrototypeDescriptor>, Compare> Signatures;
259 auto InsertToSignatureSet =
260 [&](const SmallVector<PrototypeDescriptor> &Signature) {
261 if (Signature.empty())
262 return;
264 Signatures.insert(Signature);
267 assert(!SemaRecords.empty());
269 for (const SemaRecord &SR : SemaRecords) {
270 InsertToSignatureSet(SR.Prototype);
271 InsertToSignatureSet(SR.Suffix);
272 InsertToSignatureSet(SR.OverloadedSuffix);
275 for (auto &Sig : Signatures)
276 insert(Sig);
279 void SemaSignatureTable::insert(ArrayRef<PrototypeDescriptor> Signature) {
280 if (getIndex(Signature) != INVALID_INDEX)
281 return;
283 // Insert Signature into SignatureTable if not found in the table.
284 SignatureTable.insert(SignatureTable.begin(), Signature.begin(),
285 Signature.end());
288 unsigned SemaSignatureTable::getIndex(ArrayRef<PrototypeDescriptor> Signature) {
289 // Empty signature could be point into any index since there is length
290 // field when we use, so just always point it to 0.
291 if (Signature.empty())
292 return 0;
294 // Checking Signature already in table or not.
295 if (Signature.size() <= SignatureTable.size()) {
296 size_t Bound = SignatureTable.size() - Signature.size() + 1;
297 for (size_t Index = 0; Index < Bound; ++Index) {
298 if (equal(Signature.begin(), Signature.end(),
299 SignatureTable.begin() + Index))
300 return Index;
304 return INVALID_INDEX;
307 void SemaSignatureTable::print(raw_ostream &OS) {
308 for (const auto &Sig : SignatureTable)
309 OS << "PrototypeDescriptor(" << static_cast<int>(Sig.PT) << ", "
310 << static_cast<int>(Sig.VTM) << ", " << static_cast<int>(Sig.TM)
311 << "),\n";
314 //===----------------------------------------------------------------------===//
315 // RVVEmitter implementation
316 //===----------------------------------------------------------------------===//
317 void RVVEmitter::createHeader(raw_ostream &OS) {
319 OS << "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics "
320 "-------------------===\n"
321 " *\n"
322 " *\n"
323 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
324 "Exceptions.\n"
325 " * See https://llvm.org/LICENSE.txt for license information.\n"
326 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
327 " *\n"
328 " *===-----------------------------------------------------------------"
329 "------===\n"
330 " */\n\n";
332 OS << "#ifndef __RISCV_VECTOR_H\n";
333 OS << "#define __RISCV_VECTOR_H\n\n";
335 OS << "#include <stdint.h>\n";
336 OS << "#include <stddef.h>\n\n";
338 OS << "#ifndef __riscv_vector\n";
339 OS << "#error \"Vector intrinsics require the vector extension.\"\n";
340 OS << "#endif\n\n";
342 OS << "#ifdef __cplusplus\n";
343 OS << "extern \"C\" {\n";
344 OS << "#endif\n\n";
346 OS << "#pragma clang riscv intrinsic vector\n\n";
348 printHeaderCode(OS);
350 auto printType = [&](auto T) {
351 OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr()
352 << ";\n";
355 constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3};
356 // Print RVV boolean types.
357 for (int Log2LMUL : Log2LMULs) {
358 auto T = TypeCache.computeType(BasicType::Int8, Log2LMUL,
359 PrototypeDescriptor::Mask);
360 if (T)
361 printType(*T);
363 // Print RVV int/float types.
364 for (char I : StringRef("csil")) {
365 BasicType BT = ParseBasicType(I);
366 for (int Log2LMUL : Log2LMULs) {
367 auto T = TypeCache.computeType(BT, Log2LMUL, PrototypeDescriptor::Vector);
368 if (T) {
369 printType(*T);
370 auto UT = TypeCache.computeType(
371 BT, Log2LMUL,
372 PrototypeDescriptor(BaseTypeModifier::Vector,
373 VectorTypeModifier::NoModifier,
374 TypeModifier::UnsignedInteger));
375 printType(*UT);
377 for (int NF = 2; NF <= 8; ++NF) {
378 auto TupleT = TypeCache.computeType(
379 BT, Log2LMUL,
380 PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF),
381 TypeModifier::SignedInteger));
382 auto TupleUT = TypeCache.computeType(
383 BT, Log2LMUL,
384 PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF),
385 TypeModifier::UnsignedInteger));
386 if (TupleT)
387 printType(*TupleT);
388 if (TupleUT)
389 printType(*TupleUT);
394 for (BasicType BT : {BasicType::Float16, BasicType::Float32,
395 BasicType::Float64, BasicType::BFloat16}) {
396 for (int Log2LMUL : Log2LMULs) {
397 auto T = TypeCache.computeType(BT, Log2LMUL, PrototypeDescriptor::Vector);
398 if (T)
399 printType(*T);
400 for (int NF = 2; NF <= 8; ++NF) {
401 auto TupleT = TypeCache.computeType(
402 BT, Log2LMUL,
403 PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF),
404 (BT == BasicType::BFloat16
405 ? TypeModifier::BFloat
406 : TypeModifier::Float)));
407 if (TupleT)
408 printType(*TupleT);
413 OS << "#define __riscv_v_intrinsic_overloading 1\n";
415 OS << "\n#ifdef __cplusplus\n";
416 OS << "}\n";
417 OS << "#endif // __cplusplus\n";
418 OS << "#endif // __RISCV_VECTOR_H\n";
421 void RVVEmitter::createBuiltins(raw_ostream &OS) {
422 std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
423 createRVVIntrinsics(Defs);
425 // Map to keep track of which builtin names have already been emitted.
426 StringMap<RVVIntrinsic *> BuiltinMap;
428 OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n";
429 OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, "
430 "ATTRS, \"zve32x\")\n";
431 OS << "#endif\n";
432 for (auto &Def : Defs) {
433 auto P =
434 BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get()));
435 if (!P.second) {
436 // Verf that this would have produced the same builtin definition.
437 if (P.first->second->hasBuiltinAlias() != Def->hasBuiltinAlias())
438 PrintFatalError("Builtin with same name has different hasAutoDef");
439 else if (!Def->hasBuiltinAlias() &&
440 P.first->second->getBuiltinTypeStr() != Def->getBuiltinTypeStr())
441 PrintFatalError("Builtin with same name has different type string");
442 continue;
444 OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getBuiltinName() << ",\"";
445 if (!Def->hasBuiltinAlias())
446 OS << Def->getBuiltinTypeStr();
447 OS << "\", \"n\")\n";
449 OS << "#undef RISCVV_BUILTIN\n";
452 void RVVEmitter::createCodeGen(raw_ostream &OS) {
453 std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
454 createRVVIntrinsics(Defs);
455 // IR name could be empty, use the stable sort preserves the relative order.
456 llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A,
457 const std::unique_ptr<RVVIntrinsic> &B) {
458 if (A->getIRName() == B->getIRName())
459 return (A->getPolicyAttrs() < B->getPolicyAttrs());
460 return (A->getIRName() < B->getIRName());
463 // Map to keep track of which builtin names have already been emitted.
464 StringMap<RVVIntrinsic *> BuiltinMap;
466 // Print switch body when the ir name, ManualCodegen or policy changes from
467 // previous iteration.
468 RVVIntrinsic *PrevDef = Defs.begin()->get();
469 for (auto &Def : Defs) {
470 StringRef CurIRName = Def->getIRName();
471 if (CurIRName != PrevDef->getIRName() ||
472 (Def->getManualCodegen() != PrevDef->getManualCodegen()) ||
473 (Def->getPolicyAttrs() != PrevDef->getPolicyAttrs())) {
474 emitCodeGenSwitchBody(PrevDef, OS);
476 PrevDef = Def.get();
478 auto P =
479 BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get()));
480 if (P.second) {
481 OS << "case RISCVVector::BI__builtin_rvv_" << Def->getBuiltinName()
482 << ":\n";
483 continue;
486 if (P.first->second->getIRName() != Def->getIRName())
487 PrintFatalError("Builtin with same name has different IRName");
488 else if (P.first->second->getManualCodegen() != Def->getManualCodegen())
489 PrintFatalError("Builtin with same name has different ManualCodegen");
490 else if (P.first->second->isMasked() != Def->isMasked())
491 PrintFatalError("Builtin with same name has different isMasked");
492 else if (P.first->second->hasVL() != Def->hasVL())
493 PrintFatalError("Builtin with same name has different hasVL");
494 else if (P.first->second->getPolicyScheme() != Def->getPolicyScheme())
495 PrintFatalError("Builtin with same name has different getPolicyScheme");
496 else if (P.first->second->getIntrinsicTypes() != Def->getIntrinsicTypes())
497 PrintFatalError("Builtin with same name has different IntrinsicTypes");
499 emitCodeGenSwitchBody(Defs.back().get(), OS);
500 OS << "\n";
503 void RVVEmitter::createRVVIntrinsics(
504 std::vector<std::unique_ptr<RVVIntrinsic>> &Out,
505 std::vector<SemaRecord> *SemaRecords) {
506 std::vector<Record *> RV = Records.getAllDerivedDefinitions("RVVBuiltin");
507 for (auto *R : RV) {
508 StringRef Name = R->getValueAsString("Name");
509 StringRef SuffixProto = R->getValueAsString("Suffix");
510 StringRef OverloadedName = R->getValueAsString("OverloadedName");
511 StringRef OverloadedSuffixProto = R->getValueAsString("OverloadedSuffix");
512 StringRef Prototypes = R->getValueAsString("Prototype");
513 StringRef TypeRange = R->getValueAsString("TypeRange");
514 bool HasMasked = R->getValueAsBit("HasMasked");
515 bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand");
516 bool HasVL = R->getValueAsBit("HasVL");
517 Record *MPSRecord = R->getValueAsDef("MaskedPolicyScheme");
518 auto MaskedPolicyScheme =
519 static_cast<PolicyScheme>(MPSRecord->getValueAsInt("Value"));
520 Record *UMPSRecord = R->getValueAsDef("UnMaskedPolicyScheme");
521 auto UnMaskedPolicyScheme =
522 static_cast<PolicyScheme>(UMPSRecord->getValueAsInt("Value"));
523 std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL");
524 bool HasTailPolicy = R->getValueAsBit("HasTailPolicy");
525 bool HasMaskPolicy = R->getValueAsBit("HasMaskPolicy");
526 bool SupportOverloading = R->getValueAsBit("SupportOverloading");
527 bool HasBuiltinAlias = R->getValueAsBit("HasBuiltinAlias");
528 StringRef ManualCodegen = R->getValueAsString("ManualCodegen");
529 std::vector<int64_t> IntrinsicTypes =
530 R->getValueAsListOfInts("IntrinsicTypes");
531 std::vector<StringRef> RequiredFeatures =
532 R->getValueAsListOfStrings("RequiredFeatures");
533 StringRef IRName = R->getValueAsString("IRName");
534 StringRef MaskedIRName = R->getValueAsString("MaskedIRName");
535 unsigned NF = R->getValueAsInt("NF");
536 bool IsTuple = R->getValueAsBit("IsTuple");
537 bool HasFRMRoundModeOp = R->getValueAsBit("HasFRMRoundModeOp");
539 const Policy DefaultPolicy;
540 SmallVector<Policy> SupportedUnMaskedPolicies =
541 RVVIntrinsic::getSupportedUnMaskedPolicies();
542 SmallVector<Policy> SupportedMaskedPolicies =
543 RVVIntrinsic::getSupportedMaskedPolicies(HasTailPolicy, HasMaskPolicy);
545 // Parse prototype and create a list of primitive type with transformers
546 // (operand) in Prototype. Prototype[0] is output operand.
547 SmallVector<PrototypeDescriptor> BasicPrototype =
548 parsePrototypes(Prototypes);
550 SmallVector<PrototypeDescriptor> SuffixDesc = parsePrototypes(SuffixProto);
551 SmallVector<PrototypeDescriptor> OverloadedSuffixDesc =
552 parsePrototypes(OverloadedSuffixProto);
554 // Compute Builtin types
555 auto Prototype = RVVIntrinsic::computeBuiltinTypes(
556 BasicPrototype, /*IsMasked=*/false,
557 /*HasMaskedOffOperand=*/false, HasVL, NF, UnMaskedPolicyScheme,
558 DefaultPolicy, IsTuple);
559 llvm::SmallVector<PrototypeDescriptor> MaskedPrototype;
560 if (HasMasked)
561 MaskedPrototype = RVVIntrinsic::computeBuiltinTypes(
562 BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, NF,
563 MaskedPolicyScheme, DefaultPolicy, IsTuple);
565 // Create Intrinsics for each type and LMUL.
566 for (char I : TypeRange) {
567 for (int Log2LMUL : Log2LMULList) {
568 BasicType BT = ParseBasicType(I);
569 std::optional<RVVTypes> Types =
570 TypeCache.computeTypes(BT, Log2LMUL, NF, Prototype);
571 // Ignored to create new intrinsic if there are any illegal types.
572 if (!Types)
573 continue;
575 auto SuffixStr =
576 RVVIntrinsic::getSuffixStr(TypeCache, BT, Log2LMUL, SuffixDesc);
577 auto OverloadedSuffixStr = RVVIntrinsic::getSuffixStr(
578 TypeCache, BT, Log2LMUL, OverloadedSuffixDesc);
579 // Create a unmasked intrinsic
580 Out.push_back(std::make_unique<RVVIntrinsic>(
581 Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName,
582 /*IsMasked=*/false, /*HasMaskedOffOperand=*/false, HasVL,
583 UnMaskedPolicyScheme, SupportOverloading, HasBuiltinAlias,
584 ManualCodegen, *Types, IntrinsicTypes, RequiredFeatures, NF,
585 DefaultPolicy, HasFRMRoundModeOp));
586 if (UnMaskedPolicyScheme != PolicyScheme::SchemeNone)
587 for (auto P : SupportedUnMaskedPolicies) {
588 SmallVector<PrototypeDescriptor> PolicyPrototype =
589 RVVIntrinsic::computeBuiltinTypes(
590 BasicPrototype, /*IsMasked=*/false,
591 /*HasMaskedOffOperand=*/false, HasVL, NF,
592 UnMaskedPolicyScheme, P, IsTuple);
593 std::optional<RVVTypes> PolicyTypes =
594 TypeCache.computeTypes(BT, Log2LMUL, NF, PolicyPrototype);
595 Out.push_back(std::make_unique<RVVIntrinsic>(
596 Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName,
597 /*IsMask=*/false, /*HasMaskedOffOperand=*/false, HasVL,
598 UnMaskedPolicyScheme, SupportOverloading, HasBuiltinAlias,
599 ManualCodegen, *PolicyTypes, IntrinsicTypes, RequiredFeatures,
600 NF, P, HasFRMRoundModeOp));
602 if (!HasMasked)
603 continue;
604 // Create a masked intrinsic
605 std::optional<RVVTypes> MaskTypes =
606 TypeCache.computeTypes(BT, Log2LMUL, NF, MaskedPrototype);
607 Out.push_back(std::make_unique<RVVIntrinsic>(
608 Name, SuffixStr, OverloadedName, OverloadedSuffixStr, MaskedIRName,
609 /*IsMasked=*/true, HasMaskedOffOperand, HasVL, MaskedPolicyScheme,
610 SupportOverloading, HasBuiltinAlias, ManualCodegen, *MaskTypes,
611 IntrinsicTypes, RequiredFeatures, NF, DefaultPolicy,
612 HasFRMRoundModeOp));
613 if (MaskedPolicyScheme == PolicyScheme::SchemeNone)
614 continue;
615 for (auto P : SupportedMaskedPolicies) {
616 SmallVector<PrototypeDescriptor> PolicyPrototype =
617 RVVIntrinsic::computeBuiltinTypes(
618 BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL,
619 NF, MaskedPolicyScheme, P, IsTuple);
620 std::optional<RVVTypes> PolicyTypes =
621 TypeCache.computeTypes(BT, Log2LMUL, NF, PolicyPrototype);
622 Out.push_back(std::make_unique<RVVIntrinsic>(
623 Name, SuffixStr, OverloadedName, OverloadedSuffixStr,
624 MaskedIRName, /*IsMasked=*/true, HasMaskedOffOperand, HasVL,
625 MaskedPolicyScheme, SupportOverloading, HasBuiltinAlias,
626 ManualCodegen, *PolicyTypes, IntrinsicTypes, RequiredFeatures, NF,
627 P, HasFRMRoundModeOp));
629 } // End for Log2LMULList
630 } // End for TypeRange
632 // We don't emit vsetvli and vsetvlimax for SemaRecord.
633 // They are written in riscv_vector.td and will emit those marco define in
634 // riscv_vector.h
635 if (Name == "vsetvli" || Name == "vsetvlimax")
636 continue;
638 if (!SemaRecords)
639 continue;
641 // Create SemaRecord
642 SemaRecord SR;
643 SR.Name = Name.str();
644 SR.OverloadedName = OverloadedName.str();
645 BasicType TypeRangeMask = BasicType::Unknown;
646 for (char I : TypeRange)
647 TypeRangeMask |= ParseBasicType(I);
649 SR.TypeRangeMask = static_cast<unsigned>(TypeRangeMask);
651 unsigned Log2LMULMask = 0;
652 for (int Log2LMUL : Log2LMULList)
653 Log2LMULMask |= 1 << (Log2LMUL + 3);
655 SR.Log2LMULMask = Log2LMULMask;
657 SR.RequiredExtensions = 0;
658 for (auto RequiredFeature : RequiredFeatures) {
659 RVVRequire RequireExt = StringSwitch<RVVRequire>(RequiredFeature)
660 .Case("RV64", RVV_REQ_RV64)
661 .Case("ZvfhminOrZvfh", RVV_REQ_ZvfhminOrZvfh)
662 .Case("Xsfvcp", RVV_REQ_Xsfvcp)
663 .Case("Xsfvfnrclipxfqf", RVV_REQ_Xsfvfnrclipxfqf)
664 .Case("Xsfvfwmaccqqq", RVV_REQ_Xsfvfwmaccqqq)
665 .Case("Xsfvqmaccdod", RVV_REQ_Xsfvqmaccdod)
666 .Case("Xsfvqmaccqoq", RVV_REQ_Xsfvqmaccqoq)
667 .Case("Zvbb", RVV_REQ_Zvbb)
668 .Case("Zvbc", RVV_REQ_Zvbc)
669 .Case("Zvkb", RVV_REQ_Zvkb)
670 .Case("Zvkg", RVV_REQ_Zvkg)
671 .Case("Zvkned", RVV_REQ_Zvkned)
672 .Case("Zvknha", RVV_REQ_Zvknha)
673 .Case("Zvknhb", RVV_REQ_Zvknhb)
674 .Case("Zvksed", RVV_REQ_Zvksed)
675 .Case("Zvksh", RVV_REQ_Zvksh)
676 .Default(RVV_REQ_None);
677 assert(RequireExt != RVV_REQ_None && "Unrecognized required feature?");
678 SR.RequiredExtensions |= RequireExt;
681 SR.NF = NF;
682 SR.HasMasked = HasMasked;
683 SR.HasVL = HasVL;
684 SR.HasMaskedOffOperand = HasMaskedOffOperand;
685 SR.HasTailPolicy = HasTailPolicy;
686 SR.HasMaskPolicy = HasMaskPolicy;
687 SR.UnMaskedPolicyScheme = static_cast<uint8_t>(UnMaskedPolicyScheme);
688 SR.MaskedPolicyScheme = static_cast<uint8_t>(MaskedPolicyScheme);
689 SR.Prototype = std::move(BasicPrototype);
690 SR.Suffix = parsePrototypes(SuffixProto);
691 SR.OverloadedSuffix = parsePrototypes(OverloadedSuffixProto);
692 SR.IsTuple = IsTuple;
693 SR.HasFRMRoundModeOp = HasFRMRoundModeOp;
695 SemaRecords->push_back(SR);
699 void RVVEmitter::printHeaderCode(raw_ostream &OS) {
700 std::vector<Record *> RVVHeaders =
701 Records.getAllDerivedDefinitions("RVVHeader");
702 for (auto *R : RVVHeaders) {
703 StringRef HeaderCodeStr = R->getValueAsString("HeaderCode");
704 OS << HeaderCodeStr.str();
708 void RVVEmitter::createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out,
709 SemaSignatureTable &SST,
710 ArrayRef<SemaRecord> SemaRecords) {
711 SST.init(SemaRecords);
713 for (const auto &SR : SemaRecords) {
714 Out.emplace_back(RVVIntrinsicRecord());
715 RVVIntrinsicRecord &R = Out.back();
716 R.Name = SR.Name.c_str();
717 R.OverloadedName = SR.OverloadedName.c_str();
718 R.PrototypeIndex = SST.getIndex(SR.Prototype);
719 R.SuffixIndex = SST.getIndex(SR.Suffix);
720 R.OverloadedSuffixIndex = SST.getIndex(SR.OverloadedSuffix);
721 R.PrototypeLength = SR.Prototype.size();
722 R.SuffixLength = SR.Suffix.size();
723 R.OverloadedSuffixSize = SR.OverloadedSuffix.size();
724 R.RequiredExtensions = SR.RequiredExtensions;
725 R.TypeRangeMask = SR.TypeRangeMask;
726 R.Log2LMULMask = SR.Log2LMULMask;
727 R.NF = SR.NF;
728 R.HasMasked = SR.HasMasked;
729 R.HasVL = SR.HasVL;
730 R.HasMaskedOffOperand = SR.HasMaskedOffOperand;
731 R.HasTailPolicy = SR.HasTailPolicy;
732 R.HasMaskPolicy = SR.HasMaskPolicy;
733 R.UnMaskedPolicyScheme = SR.UnMaskedPolicyScheme;
734 R.MaskedPolicyScheme = SR.MaskedPolicyScheme;
735 R.IsTuple = SR.IsTuple;
736 R.HasFRMRoundModeOp = SR.HasFRMRoundModeOp;
738 assert(R.PrototypeIndex !=
739 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX));
740 assert(R.SuffixIndex !=
741 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX));
742 assert(R.OverloadedSuffixIndex !=
743 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX));
747 void RVVEmitter::createSema(raw_ostream &OS) {
748 std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
749 std::vector<RVVIntrinsicRecord> RVVIntrinsicRecords;
750 SemaSignatureTable SST;
751 std::vector<SemaRecord> SemaRecords;
753 createRVVIntrinsics(Defs, &SemaRecords);
755 createRVVIntrinsicRecords(RVVIntrinsicRecords, SST, SemaRecords);
757 // Emit signature table for SemaRISCVVectorLookup.cpp.
758 OS << "#ifdef DECL_SIGNATURE_TABLE\n";
759 SST.print(OS);
760 OS << "#endif\n";
762 // Emit RVVIntrinsicRecords for SemaRISCVVectorLookup.cpp.
763 OS << "#ifdef DECL_INTRINSIC_RECORDS\n";
764 for (const RVVIntrinsicRecord &Record : RVVIntrinsicRecords)
765 OS << Record;
766 OS << "#endif\n";
769 namespace clang {
770 void EmitRVVHeader(RecordKeeper &Records, raw_ostream &OS) {
771 RVVEmitter(Records).createHeader(OS);
774 void EmitRVVBuiltins(RecordKeeper &Records, raw_ostream &OS) {
775 RVVEmitter(Records).createBuiltins(OS);
778 void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
779 RVVEmitter(Records).createCodeGen(OS);
782 void EmitRVVBuiltinSema(RecordKeeper &Records, raw_ostream &OS) {
783 RVVEmitter(Records).createSema(OS);
786 } // End namespace clang