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 unsigned IndexedLoadStorePtrIdx = getIndexedLoadStorePtrIdx(RVVI);
254 if (IndexedLoadStorePtrIdx != UnknownIndex) {
255 OS << " {\n";
256 OS << " auto PointeeType = E->getArg(" << IndexedLoadStorePtrIdx
257 << ")->getType()->getPointeeType();\n";
258 OS << " SegInstSEW = "
259 "llvm::Log2_64(getContext().getTypeSize(PointeeType));\n";
260 OS << " }\n";
261 } else {
262 OS << " SegInstSEW = " << getSegInstLog2SEW(InstName: RVVI->getOverloadedName())
263 << ";\n";
264 }
265
266 if (RVVI->hasManualCodegen()) {
267 OS << "IsMasked = " << (RVVI->isMasked() ? "true" : "false") << ";\n";
268 OS << RVVI->getManualCodegen();
269 OS << "break;\n";
270 return;
271 }
272
273 for (const auto &I : enumerate(First: RVVI->getInputTypes())) {
274 if (I.value()->isPointer()) {
275 assert(RVVI->getIntrinsicTypes().front() == -1 &&
276 "RVVI should be vector load intrinsic.");
277 }
278 }
279
280 if (RVVI->isMasked()) {
281 if (RVVI->hasVL()) {
282 OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n";
283 if (RVVI->hasPolicyOperand())
284 OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(),"
285 " PolicyAttrs));\n";
286 if (RVVI->hasMaskedOffOperand() && RVVI->getPolicyAttrs().isTAMAPolicy())
287 OS << " Ops.insert(Ops.begin(), "
288 "llvm::PoisonValue::get(ResultType));\n";
289 // Masked reduction cases.
290 if (!RVVI->hasMaskedOffOperand() && RVVI->hasPassthruOperand() &&
291 RVVI->getPolicyAttrs().isTAMAPolicy())
292 OS << " Ops.insert(Ops.begin(), "
293 "llvm::PoisonValue::get(ResultType));\n";
294 } else {
295 OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n";
296 }
297 } else {
298 if (RVVI->hasPolicyOperand())
299 OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(), "
300 "PolicyAttrs));\n";
301 else if (RVVI->hasPassthruOperand() && RVVI->getPolicyAttrs().isTAPolicy())
302 OS << " Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));\n";
303 }
304
305 if (RVVI->getTWiden() > 0)
306 OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(), TWiden));\n";
307
308 OS << " IntrinsicTypes = {";
309 ListSeparator LS;
310 for (const auto &Idx : RVVI->getIntrinsicTypes()) {
311 if (Idx == -1)
312 OS << LS << "ResultType";
313 else
314 OS << LS << "Ops[" << Idx << "]->getType()";
315 }
316
317 // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is
318 // always last operand.
319 if (RVVI->hasVL())
320 OS << ", Ops.back()->getType()";
321 OS << "};\n";
322 OS << " break;\n";
323}
324
325//===----------------------------------------------------------------------===//
326// SemaSignatureTable implementation
327//===----------------------------------------------------------------------===//
328void SemaSignatureTable::init(ArrayRef<SemaRecord> SemaRecords) {
329 // Sort signature entries by length, let longer signature insert first, to
330 // make it more possible to reuse table entries, that can reduce ~10% table
331 // size.
332 struct Compare {
333 bool operator()(const SmallVector<PrototypeDescriptor> &A,
334 const SmallVector<PrototypeDescriptor> &B) const {
335 if (A.size() != B.size())
336 return A.size() > B.size();
337
338 size_t Len = A.size();
339 for (size_t i = 0; i < Len; ++i) {
340 if (A[i] != B[i])
341 return A[i] < B[i];
342 }
343
344 return false;
345 }
346 };
347
348 std::set<SmallVector<PrototypeDescriptor>, Compare> Signatures;
349 auto InsertToSignatureSet =
350 [&](const SmallVector<PrototypeDescriptor> &Signature) {
351 if (Signature.empty())
352 return;
353
354 Signatures.insert(x: Signature);
355 };
356
357 assert(!SemaRecords.empty());
358
359 for (const SemaRecord &SR : SemaRecords) {
360 InsertToSignatureSet(SR.Prototype);
361 InsertToSignatureSet(SR.Suffix);
362 InsertToSignatureSet(SR.OverloadedSuffix);
363 }
364
365 for (auto &Sig : Signatures)
366 insert(Signature: Sig);
367}
368
369void SemaSignatureTable::insert(ArrayRef<PrototypeDescriptor> Signature) {
370 if (getIndex(Signature) != INVALID_INDEX)
371 return;
372
373 // Insert Signature into SignatureTable if not found in the table.
374 SignatureTable.insert(position: SignatureTable.begin(), first: Signature.begin(),
375 last: Signature.end());
376}
377
378unsigned SemaSignatureTable::getIndex(ArrayRef<PrototypeDescriptor> Signature) {
379 // Empty signature could be point into any index since there is length
380 // field when we use, so just always point it to 0.
381 if (Signature.empty())
382 return 0;
383
384 // Checking Signature already in table or not.
385 if (Signature.size() <= SignatureTable.size()) {
386 size_t Bound = SignatureTable.size() - Signature.size() + 1;
387 for (size_t Index = 0; Index < Bound; ++Index) {
388 if (equal(first1: Signature.begin(), last1: Signature.end(),
389 first2: SignatureTable.begin() + Index))
390 return Index;
391 }
392 }
393
394 return INVALID_INDEX;
395}
396
397void SemaSignatureTable::print(raw_ostream &OS) {
398 for (const auto &Sig : SignatureTable)
399 OS << "PrototypeDescriptor(" << static_cast<int>(Sig.PT) << ", "
400 << static_cast<int>(Sig.VTM) << ", " << static_cast<int>(Sig.TM)
401 << "),\n";
402}
403
404//===----------------------------------------------------------------------===//
405// RVVEmitter implementation
406//===----------------------------------------------------------------------===//
407void RVVEmitter::createHeader(raw_ostream &OS) {
408
409 OS << "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics "
410 "-------------------===\n"
411 " *\n"
412 " *\n"
413 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
414 "Exceptions.\n"
415 " * See https://llvm.org/LICENSE.txt for license information.\n"
416 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
417 " *\n"
418 " *===-----------------------------------------------------------------"
419 "------===\n"
420 " */\n\n";
421
422 OS << "#ifndef __RISCV_VECTOR_H\n";
423 OS << "#define __RISCV_VECTOR_H\n\n";
424
425 OS << "#include <stdint.h>\n";
426 OS << "#include <stddef.h>\n\n";
427
428 OS << "#ifdef __cplusplus\n";
429 OS << "extern \"C\" {\n";
430 OS << "#endif\n\n";
431
432 OS << "#pragma clang riscv intrinsic vector\n\n";
433
434 printHeaderCode(OS);
435
436 auto printType = [&](auto T) {
437 OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr()
438 << ";\n";
439 };
440
441 constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3};
442 // Print RVV boolean types.
443 for (int Log2LMUL : Log2LMULs) {
444 auto T = TypeCache.computeType(BT: BasicType::Int8, Log2LMUL,
445 Proto: PrototypeDescriptor::Mask);
446 if (T)
447 printType(*T);
448 }
449 // Print RVV int/float types.
450 for (char I : StringRef("csil")) {
451 BasicType BT = ParseBasicType(c: I);
452 for (int Log2LMUL : Log2LMULs) {
453 auto T = TypeCache.computeType(BT, Log2LMUL, Proto: PrototypeDescriptor::Vector);
454 if (T) {
455 printType(*T);
456 auto UT = TypeCache.computeType(
457 BT, Log2LMUL,
458 Proto: PrototypeDescriptor(BaseTypeModifier::Vector,
459 VectorTypeModifier::NoModifier,
460 TypeModifier::UnsignedInteger));
461 printType(*UT);
462 }
463 for (int NF = 2; NF <= 8; ++NF) {
464 auto TupleT = TypeCache.computeType(
465 BT, Log2LMUL,
466 Proto: PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF),
467 TypeModifier::SignedInteger));
468 auto TupleUT = TypeCache.computeType(
469 BT, Log2LMUL,
470 Proto: PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF),
471 TypeModifier::UnsignedInteger));
472 if (TupleT)
473 printType(*TupleT);
474 if (TupleUT)
475 printType(*TupleUT);
476 }
477 }
478 }
479
480 for (BasicType BT : {BasicType::Float16, BasicType::Float32,
481 BasicType::Float64, BasicType::BFloat16}) {
482 for (int Log2LMUL : Log2LMULs) {
483 auto T = TypeCache.computeType(BT, Log2LMUL, Proto: PrototypeDescriptor::Vector);
484 if (T)
485 printType(*T);
486 for (int NF = 2; NF <= 8; ++NF) {
487 auto TupleT = TypeCache.computeType(
488 BT, Log2LMUL,
489 Proto: PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF),
490 (BT == BasicType::BFloat16
491 ? TypeModifier::BFloat
492 : TypeModifier::Float)));
493 if (TupleT)
494 printType(*TupleT);
495 }
496 }
497 }
498
499 OS << "\n#ifdef __cplusplus\n";
500 OS << "}\n";
501 OS << "#endif // __cplusplus\n";
502 OS << "#endif // __RISCV_VECTOR_H\n";
503}
504
505void RVVEmitter::createBuiltins(raw_ostream &OS) {
506 std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
507 createRVVIntrinsics(Out&: Defs);
508
509 llvm::StringToOffsetTable Table;
510 // Ensure offset zero is the empty string.
511 Table.GetOrAddStringOffset(Str: "");
512 // Hard coded strings used in the builtin structures.
513 Table.GetOrAddStringOffset(Str: "n");
514 Table.GetOrAddStringOffset(Str: "zve32x");
515
516 // Map to unique the builtin names.
517 StringMap<RVVIntrinsic *> BuiltinMap;
518 std::vector<RVVIntrinsic *> UniqueDefs;
519 for (auto &Def : Defs) {
520 auto P = BuiltinMap.insert(KV: {Def->getBuiltinName(), Def.get()});
521 if (P.second) {
522 Table.GetOrAddStringOffset(Str: Def->getBuiltinName());
523 if (!Def->hasBuiltinAlias())
524 Table.GetOrAddStringOffset(Str: Def->getBuiltinTypeStr());
525 UniqueDefs.push_back(x: Def.get());
526 continue;
527 }
528
529 // Verf that this would have produced the same builtin definition.
530 if (P.first->second->hasBuiltinAlias() != Def->hasBuiltinAlias())
531 PrintFatalError(Msg: "Builtin with same name has different hasAutoDef");
532 else if (!Def->hasBuiltinAlias() &&
533 P.first->second->getBuiltinTypeStr() != Def->getBuiltinTypeStr())
534 PrintFatalError(Msg: "Builtin with same name has different type string");
535 }
536
537 // Emit the enumerators of RVV builtins. Note that these are emitted without
538 // any outer context to enable concatenating them.
539 OS << "// RISCV Vector builtin enumerators\n";
540 OS << "#ifdef GET_RISCVV_BUILTIN_ENUMERATORS\n";
541 for (RVVIntrinsic *Def : UniqueDefs)
542 OS << " BI__builtin_rvv_" << Def->getBuiltinName() << ",\n";
543 OS << "#endif // GET_RISCVV_BUILTIN_ENUMERATORS\n\n";
544
545 // Emit the string table for the RVV builtins.
546 OS << "// RISCV Vector builtin enumerators\n";
547 OS << "#ifdef GET_RISCVV_BUILTIN_STR_TABLE\n";
548 Table.EmitStringTableDef(OS, Name: "BuiltinStrings");
549 OS << "#endif // GET_RISCVV_BUILTIN_STR_TABLE\n\n";
550
551 // Emit the info structs of RVV builtins. Note that these are emitted without
552 // any outer context to enable concatenating them.
553 OS << "// RISCV Vector builtin infos\n";
554 OS << "#ifdef GET_RISCVV_BUILTIN_INFOS\n";
555 for (RVVIntrinsic *Def : UniqueDefs) {
556 OS << " Builtin::Info{Builtin::Info::StrOffsets{"
557 << Table.GetStringOffset(Str: Def->getBuiltinName()) << " /* "
558 << Def->getBuiltinName() << " */, ";
559 if (Def->hasBuiltinAlias()) {
560 OS << "0, ";
561 } else {
562 OS << Table.GetStringOffset(Str: Def->getBuiltinTypeStr()) << " /* "
563 << Def->getBuiltinTypeStr() << " */, ";
564 }
565 OS << Table.GetStringOffset(Str: "n") << " /* n */, ";
566 OS << Table.GetStringOffset(Str: "zve32x") << " /* zve32x */}, ";
567
568 OS << "HeaderDesc::NO_HEADER, ALL_LANGUAGES},\n";
569 }
570 OS << "#endif // GET_RISCVV_BUILTIN_INFOS\n\n";
571}
572
573void RVVEmitter::createCodeGen(raw_ostream &OS) {
574 std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
575 createRVVIntrinsics(Out&: Defs);
576 // IR name could be empty, use the stable sort preserves the relative order.
577 stable_sort(Range&: Defs, C: [](const std::unique_ptr<RVVIntrinsic> &A,
578 const std::unique_ptr<RVVIntrinsic> &B) {
579 if (A->getIRName() == B->getIRName())
580 return (A->getPolicyAttrs() < B->getPolicyAttrs());
581 return (A->getIRName() < B->getIRName());
582 });
583
584 // Map to keep track of which builtin names have already been emitted.
585 StringMap<RVVIntrinsic *> BuiltinMap;
586
587 // Print switch body when the ir name, ManualCodegen, policy or log2sew
588 // changes from previous iteration.
589 RVVIntrinsic *PrevDef = Defs.begin()->get();
590 for (auto &Def : Defs) {
591 StringRef CurIRName = Def->getIRName();
592 if (CurIRName != PrevDef->getIRName() ||
593 (Def->getManualCodegen() != PrevDef->getManualCodegen()) ||
594 (Def->getPolicyAttrs() != PrevDef->getPolicyAttrs()) ||
595 (getSegInstLog2SEW(InstName: Def->getOverloadedName()) !=
596 getSegInstLog2SEW(InstName: PrevDef->getOverloadedName())) ||
597 (Def->getTWiden() != PrevDef->getTWiden())) {
598 emitCodeGenSwitchBody(RVVI: PrevDef, OS);
599 }
600 PrevDef = Def.get();
601
602 auto P =
603 BuiltinMap.insert(KV: std::make_pair(x: Def->getBuiltinName(), y: Def.get()));
604 if (P.second) {
605 OS << "case RISCVVector::BI__builtin_rvv_" << Def->getBuiltinName()
606 << ":\n";
607 continue;
608 }
609
610 if (P.first->second->getIRName() != Def->getIRName())
611 PrintFatalError(Msg: "Builtin with same name has different IRName");
612 else if (P.first->second->getManualCodegen() != Def->getManualCodegen())
613 PrintFatalError(Msg: "Builtin with same name has different ManualCodegen");
614 else if (P.first->second->isMasked() != Def->isMasked())
615 PrintFatalError(Msg: "Builtin with same name has different isMasked");
616 else if (P.first->second->hasVL() != Def->hasVL())
617 PrintFatalError(Msg: "Builtin with same name has different hasVL");
618 else if (P.first->second->getPolicyScheme() != Def->getPolicyScheme())
619 PrintFatalError(Msg: "Builtin with same name has different getPolicyScheme");
620 else if (P.first->second->getIntrinsicTypes() != Def->getIntrinsicTypes())
621 PrintFatalError(Msg: "Builtin with same name has different IntrinsicTypes");
622 }
623 emitCodeGenSwitchBody(RVVI: Defs.back().get(), OS);
624 OS << "\n";
625}
626
627void RVVEmitter::createRVVIntrinsics(
628 std::vector<std::unique_ptr<RVVIntrinsic>> &Out,
629 std::vector<SemaRecord> *SemaRecords) {
630 for (const Record *R : Records.getAllDerivedDefinitions(ClassName: "RVVBuiltin")) {
631 StringRef Name = R->getValueAsString(FieldName: "Name");
632 StringRef SuffixProto = R->getValueAsString(FieldName: "Suffix");
633 StringRef OverloadedName = R->getValueAsString(FieldName: "OverloadedName");
634 StringRef OverloadedSuffixProto = R->getValueAsString(FieldName: "OverloadedSuffix");
635 StringRef Prototypes = R->getValueAsString(FieldName: "Prototype");
636 StringRef TypeRange = R->getValueAsString(FieldName: "TypeRange");
637 bool HasMasked = R->getValueAsBit(FieldName: "HasMasked");
638 bool HasMaskedOffOperand = R->getValueAsBit(FieldName: "HasMaskedOffOperand");
639 bool HasVL = R->getValueAsBit(FieldName: "HasVL");
640 const Record *MPSRecord = R->getValueAsDef(FieldName: "MaskedPolicyScheme");
641 auto MaskedPolicyScheme =
642 static_cast<PolicyScheme>(MPSRecord->getValueAsInt(FieldName: "Value"));
643 const Record *UMPSRecord = R->getValueAsDef(FieldName: "UnMaskedPolicyScheme");
644 auto UnMaskedPolicyScheme =
645 static_cast<PolicyScheme>(UMPSRecord->getValueAsInt(FieldName: "Value"));
646 std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts(FieldName: "Log2LMUL");
647 bool HasTailPolicy = R->getValueAsBit(FieldName: "HasTailPolicy");
648 bool HasMaskPolicy = R->getValueAsBit(FieldName: "HasMaskPolicy");
649 bool AltFmt = R->getValueAsBit(FieldName: "AltFmt");
650 bool SupportOverloading = R->getValueAsBit(FieldName: "SupportOverloading");
651 bool HasBuiltinAlias = R->getValueAsBit(FieldName: "HasBuiltinAlias");
652 StringRef ManualCodegen = R->getValueAsString(FieldName: "ManualCodegen");
653 std::vector<int64_t> IntrinsicTypes =
654 R->getValueAsListOfInts(FieldName: "IntrinsicTypes");
655 std::vector<StringRef> RequiredFeatures =
656 R->getValueAsListOfStrings(FieldName: "RequiredFeatures");
657 StringRef IRName = R->getValueAsString(FieldName: "IRName");
658 StringRef MaskedIRName = R->getValueAsString(FieldName: "MaskedIRName");
659 unsigned NF = R->getValueAsInt(FieldName: "NF");
660 unsigned TWiden = R->getValueAsInt(FieldName: "TWiden");
661 bool IsTuple = R->getValueAsBit(FieldName: "IsTuple");
662 bool HasFRMRoundModeOp = R->getValueAsBit(FieldName: "HasFRMRoundModeOp");
663
664 const Policy DefaultPolicy;
665 SmallVector<Policy> SupportedUnMaskedPolicies =
666 RVVIntrinsic::getSupportedUnMaskedPolicies();
667 SmallVector<Policy> SupportedMaskedPolicies =
668 RVVIntrinsic::getSupportedMaskedPolicies(HasTailPolicy, HasMaskPolicy);
669
670 // Parse prototype and create a list of primitive type with transformers
671 // (operand) in Prototype. Prototype[0] is output operand.
672 SmallVector<PrototypeDescriptor> BasicPrototype =
673 parsePrototypes(Prototypes);
674
675 SmallVector<PrototypeDescriptor> SuffixDesc = parsePrototypes(Prototypes: SuffixProto);
676 SmallVector<PrototypeDescriptor> OverloadedSuffixDesc =
677 parsePrototypes(Prototypes: OverloadedSuffixProto);
678
679 // Compute Builtin types
680 auto Prototype = RVVIntrinsic::computeBuiltinTypes(
681 Prototype: BasicPrototype, /*IsMasked=*/false,
682 /*HasMaskedOffOperand=*/false, HasVL, NF, DefaultScheme: UnMaskedPolicyScheme,
683 PolicyAttrs: DefaultPolicy, IsTuple);
684 SmallVector<PrototypeDescriptor> MaskedPrototype;
685 if (HasMasked)
686 MaskedPrototype = RVVIntrinsic::computeBuiltinTypes(
687 Prototype: BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, NF,
688 DefaultScheme: MaskedPolicyScheme, PolicyAttrs: DefaultPolicy, IsTuple);
689
690 // Create Intrinsics for each type and LMUL.
691 for (char I : TypeRange) {
692 for (int Log2LMUL : Log2LMULList) {
693 BasicType BT = ParseBasicType(c: I);
694 std::optional<RVVTypes> Types =
695 TypeCache.computeTypes(BT, Log2LMUL, NF, Prototype);
696 // Ignored to create new intrinsic if there are any illegal types.
697 if (!Types)
698 continue;
699
700 auto SuffixStr =
701 RVVIntrinsic::getSuffixStr(TypeCache, Type: BT, Log2LMUL, PrototypeDescriptors: SuffixDesc);
702 auto OverloadedSuffixStr = RVVIntrinsic::getSuffixStr(
703 TypeCache, Type: BT, Log2LMUL, PrototypeDescriptors: OverloadedSuffixDesc);
704 // Create a unmasked intrinsic
705 Out.push_back(x: std::make_unique<RVVIntrinsic>(
706 args&: Name, args&: SuffixStr, args&: OverloadedName, args&: OverloadedSuffixStr, args&: IRName,
707 /*IsMasked=*/args: false, /*HasMaskedOffOperand=*/args: false, args&: HasVL,
708 args&: UnMaskedPolicyScheme, args&: SupportOverloading, args&: HasBuiltinAlias,
709 args&: ManualCodegen, args&: *Types, args&: IntrinsicTypes, args&: NF, args: DefaultPolicy,
710 args&: HasFRMRoundModeOp, args&: TWiden, args&: AltFmt));
711 if (UnMaskedPolicyScheme != PolicyScheme::SchemeNone)
712 for (auto P : SupportedUnMaskedPolicies) {
713 SmallVector<PrototypeDescriptor> PolicyPrototype =
714 RVVIntrinsic::computeBuiltinTypes(
715 Prototype: BasicPrototype, /*IsMasked=*/false,
716 /*HasMaskedOffOperand=*/false, HasVL, NF,
717 DefaultScheme: UnMaskedPolicyScheme, PolicyAttrs: P, IsTuple);
718 std::optional<RVVTypes> PolicyTypes =
719 TypeCache.computeTypes(BT, Log2LMUL, NF, Prototype: PolicyPrototype);
720 Out.push_back(x: std::make_unique<RVVIntrinsic>(
721 args&: Name, args&: SuffixStr, args&: OverloadedName, args&: OverloadedSuffixStr, args&: IRName,
722 /*IsMask=*/args: false, /*HasMaskedOffOperand=*/args: false, args&: HasVL,
723 args&: UnMaskedPolicyScheme, args&: SupportOverloading, args&: HasBuiltinAlias,
724 args&: ManualCodegen, args&: *PolicyTypes, args&: IntrinsicTypes, args&: NF, args&: P,
725 args&: HasFRMRoundModeOp, args&: TWiden, args&: AltFmt));
726 }
727 if (!HasMasked)
728 continue;
729 // Create a masked intrinsic
730 std::optional<RVVTypes> MaskTypes =
731 TypeCache.computeTypes(BT, Log2LMUL, NF, Prototype: MaskedPrototype);
732 Out.push_back(x: std::make_unique<RVVIntrinsic>(
733 args&: Name, args&: SuffixStr, args&: OverloadedName, args&: OverloadedSuffixStr, args&: MaskedIRName,
734 /*IsMasked=*/args: true, args&: HasMaskedOffOperand, args&: HasVL, args&: MaskedPolicyScheme,
735 args&: SupportOverloading, args&: HasBuiltinAlias, args&: ManualCodegen, args&: *MaskTypes,
736 args&: IntrinsicTypes, args&: NF, args: DefaultPolicy, args&: HasFRMRoundModeOp, args&: TWiden,
737 args&: AltFmt));
738 if (MaskedPolicyScheme == PolicyScheme::SchemeNone)
739 continue;
740 for (auto P : SupportedMaskedPolicies) {
741 SmallVector<PrototypeDescriptor> PolicyPrototype =
742 RVVIntrinsic::computeBuiltinTypes(
743 Prototype: BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL,
744 NF, DefaultScheme: MaskedPolicyScheme, PolicyAttrs: P, IsTuple);
745 std::optional<RVVTypes> PolicyTypes =
746 TypeCache.computeTypes(BT, Log2LMUL, NF, Prototype: PolicyPrototype);
747 Out.push_back(x: std::make_unique<RVVIntrinsic>(
748 args&: Name, args&: SuffixStr, args&: OverloadedName, args&: OverloadedSuffixStr,
749 args&: MaskedIRName, /*IsMasked=*/args: true, args&: HasMaskedOffOperand, args&: HasVL,
750 args&: MaskedPolicyScheme, args&: SupportOverloading, args&: HasBuiltinAlias,
751 args&: ManualCodegen, args&: *PolicyTypes, args&: IntrinsicTypes, args&: NF, args&: P,
752 args&: HasFRMRoundModeOp, args&: TWiden, args&: AltFmt));
753 }
754 } // End for Log2LMULList
755 } // End for TypeRange
756
757 // We don't emit vsetvli and vsetvlimax for SemaRecord.
758 // They are written in riscv_vector.td and will emit those marco define in
759 // riscv_vector.h
760 if (Name == "vsetvli" || Name == "vsetvlimax")
761 continue;
762
763 if (!SemaRecords)
764 continue;
765
766 // Create SemaRecord
767 SemaRecord SR;
768 SR.Name = Name.str();
769 SR.OverloadedName = OverloadedName.str();
770 BasicType TypeRangeMask = BasicType::Unknown;
771 for (char I : TypeRange)
772 TypeRangeMask |= ParseBasicType(c: I);
773
774 SR.TypeRangeMask = static_cast<unsigned>(TypeRangeMask);
775
776 unsigned Log2LMULMask = 0;
777 for (int Log2LMUL : Log2LMULList)
778 Log2LMULMask |= 1 << (Log2LMUL + 3);
779
780 SR.Log2LMULMask = Log2LMULMask;
781 std::string RFs =
782 join(Begin: RequiredFeatures.begin(), End: RequiredFeatures.end(), Separator: ",");
783 SR.RequiredExtensions = RFs;
784 SR.NF = NF;
785 SR.HasMasked = HasMasked;
786 SR.HasVL = HasVL;
787 SR.HasMaskedOffOperand = HasMaskedOffOperand;
788 SR.HasTailPolicy = HasTailPolicy;
789 SR.HasMaskPolicy = HasMaskPolicy;
790 SR.AltFmt = AltFmt;
791 SR.UnMaskedPolicyScheme = static_cast<uint8_t>(UnMaskedPolicyScheme);
792 SR.MaskedPolicyScheme = static_cast<uint8_t>(MaskedPolicyScheme);
793 SR.Prototype = std::move(BasicPrototype);
794 SR.Suffix = parsePrototypes(Prototypes: SuffixProto);
795 SR.OverloadedSuffix = parsePrototypes(Prototypes: OverloadedSuffixProto);
796 SR.IsTuple = IsTuple;
797 SR.HasFRMRoundModeOp = HasFRMRoundModeOp;
798
799 SemaRecords->push_back(x: SR);
800 }
801}
802
803void RVVEmitter::printHeaderCode(raw_ostream &OS) {
804 for (const Record *R : Records.getAllDerivedDefinitions(ClassName: "RVVHeader")) {
805 StringRef HeaderCodeStr = R->getValueAsString(FieldName: "HeaderCode");
806 OS << HeaderCodeStr.str();
807 }
808}
809
810void RVVEmitter::createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out,
811 SemaSignatureTable &SST,
812 ArrayRef<SemaRecord> SemaRecords) {
813 SST.init(SemaRecords);
814
815 for (const auto &SR : SemaRecords) {
816 Out.emplace_back(args: RVVIntrinsicRecord());
817 RVVIntrinsicRecord &R = Out.back();
818 R.Name = SR.Name.c_str();
819 R.OverloadedName = SR.OverloadedName.c_str();
820 R.PrototypeIndex = SST.getIndex(Signature: SR.Prototype);
821 R.SuffixIndex = SST.getIndex(Signature: SR.Suffix);
822 R.OverloadedSuffixIndex = SST.getIndex(Signature: SR.OverloadedSuffix);
823 R.PrototypeLength = SR.Prototype.size();
824 R.SuffixLength = SR.Suffix.size();
825 R.OverloadedSuffixSize = SR.OverloadedSuffix.size();
826 R.RequiredExtensions = SR.RequiredExtensions.c_str();
827 R.TypeRangeMask = SR.TypeRangeMask;
828 R.Log2LMULMask = SR.Log2LMULMask;
829 R.NF = SR.NF;
830 R.HasMasked = SR.HasMasked;
831 R.HasVL = SR.HasVL;
832 R.HasMaskedOffOperand = SR.HasMaskedOffOperand;
833 R.HasTailPolicy = SR.HasTailPolicy;
834 R.HasMaskPolicy = SR.HasMaskPolicy;
835 R.AltFmt = SR.AltFmt;
836 R.UnMaskedPolicyScheme = SR.UnMaskedPolicyScheme;
837 R.MaskedPolicyScheme = SR.MaskedPolicyScheme;
838 R.IsTuple = SR.IsTuple;
839 R.HasFRMRoundModeOp = SR.HasFRMRoundModeOp;
840
841 assert(R.PrototypeIndex !=
842 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX));
843 assert(R.SuffixIndex !=
844 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX));
845 assert(R.OverloadedSuffixIndex !=
846 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX));
847 }
848}
849
850void RVVEmitter::createSema(raw_ostream &OS) {
851 std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
852 std::vector<RVVIntrinsicRecord> RVVIntrinsicRecords;
853 SemaSignatureTable SST;
854 std::vector<SemaRecord> SemaRecords;
855
856 createRVVIntrinsics(Out&: Defs, SemaRecords: &SemaRecords);
857
858 createRVVIntrinsicRecords(Out&: RVVIntrinsicRecords, SST, SemaRecords);
859
860 // Emit signature table for SemaRISCVVectorLookup.cpp.
861 OS << "#ifdef DECL_SIGNATURE_TABLE\n";
862 SST.print(OS);
863 OS << "#endif\n";
864
865 // Emit RVVIntrinsicRecords for SemaRISCVVectorLookup.cpp.
866 OS << "#ifdef DECL_INTRINSIC_RECORDS\n";
867 for (const RVVIntrinsicRecord &Record : RVVIntrinsicRecords)
868 OS << Record;
869 OS << "#endif\n";
870}
871
872namespace clang {
873void EmitRVVHeader(const RecordKeeper &Records, raw_ostream &OS) {
874 RVVEmitter(Records).createHeader(OS);
875}
876
877void EmitRVVBuiltins(const RecordKeeper &Records, raw_ostream &OS) {
878 RVVEmitter(Records).createBuiltins(OS);
879}
880
881void EmitRVVBuiltinCG(const RecordKeeper &Records, raw_ostream &OS) {
882 RVVEmitter(Records).createCodeGen(OS);
883}
884
885void EmitRVVBuiltinSema(const RecordKeeper &Records, raw_ostream &OS) {
886 RVVEmitter(Records).createSema(OS);
887}
888
889} // End namespace clang
890