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