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