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

source code of clang/utils/TableGen/RISCVVEmitter.cpp