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