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