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