1fe6060f1SDimitry Andric //===- RISCVVEmitter.cpp - Generate riscv_vector.h for use with clang -----===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric //
9fe6060f1SDimitry Andric // This tablegen backend is responsible for emitting riscv_vector.h which
10fe6060f1SDimitry Andric // includes a declaration and definition of each intrinsic functions specified
11fe6060f1SDimitry Andric // in https://github.com/riscv/rvv-intrinsic-doc.
12fe6060f1SDimitry Andric //
13fe6060f1SDimitry Andric // See also the documentation in include/clang/Basic/riscv_vector.td.
14fe6060f1SDimitry Andric //
15fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
16fe6060f1SDimitry Andric
1781ad6265SDimitry Andric #include "clang/Support/RISCVVIntrinsicUtils.h"
18fe6060f1SDimitry Andric #include "llvm/ADT/ArrayRef.h"
19fe6060f1SDimitry Andric #include "llvm/ADT/SmallSet.h"
20fe6060f1SDimitry Andric #include "llvm/ADT/StringExtras.h"
21fe6060f1SDimitry Andric #include "llvm/ADT/StringMap.h"
22fe6060f1SDimitry Andric #include "llvm/ADT/StringSet.h"
23972a253aSDimitry Andric #include "llvm/ADT/StringSwitch.h"
24fe6060f1SDimitry Andric #include "llvm/ADT/Twine.h"
25fe6060f1SDimitry Andric #include "llvm/TableGen/Error.h"
26fe6060f1SDimitry Andric #include "llvm/TableGen/Record.h"
27fe6060f1SDimitry Andric #include <numeric>
28bdd1243dSDimitry Andric #include <optional>
29fe6060f1SDimitry Andric
30fe6060f1SDimitry Andric using namespace llvm;
3181ad6265SDimitry Andric using namespace clang::RISCV;
32fe6060f1SDimitry Andric
33fe6060f1SDimitry Andric namespace {
34972a253aSDimitry Andric struct SemaRecord {
35972a253aSDimitry Andric // Intrinsic name, e.g. vadd_vv
36972a253aSDimitry Andric std::string Name;
37972a253aSDimitry Andric
38972a253aSDimitry Andric // Overloaded intrinsic name, could be empty if can be computed from Name
39972a253aSDimitry Andric // e.g. vadd
40972a253aSDimitry Andric std::string OverloadedName;
41972a253aSDimitry Andric
42972a253aSDimitry Andric // Supported type, mask of BasicType.
43972a253aSDimitry Andric unsigned TypeRangeMask;
44972a253aSDimitry Andric
45972a253aSDimitry Andric // Supported LMUL.
46972a253aSDimitry Andric unsigned Log2LMULMask;
47972a253aSDimitry Andric
48972a253aSDimitry Andric // Required extensions for this intrinsic.
49cb14a3feSDimitry Andric uint32_t RequiredExtensions;
50972a253aSDimitry Andric
51972a253aSDimitry Andric // Prototype for this intrinsic.
52972a253aSDimitry Andric SmallVector<PrototypeDescriptor> Prototype;
53972a253aSDimitry Andric
54972a253aSDimitry Andric // Suffix of intrinsic name.
55972a253aSDimitry Andric SmallVector<PrototypeDescriptor> Suffix;
56972a253aSDimitry Andric
57972a253aSDimitry Andric // Suffix of overloaded intrinsic name.
58972a253aSDimitry Andric SmallVector<PrototypeDescriptor> OverloadedSuffix;
59972a253aSDimitry Andric
60972a253aSDimitry Andric // Number of field, large than 1 if it's segment load/store.
61972a253aSDimitry Andric unsigned NF;
62972a253aSDimitry Andric
63972a253aSDimitry Andric bool HasMasked :1;
64972a253aSDimitry Andric bool HasVL :1;
65972a253aSDimitry Andric bool HasMaskedOffOperand :1;
66bdd1243dSDimitry Andric bool HasTailPolicy : 1;
67bdd1243dSDimitry Andric bool HasMaskPolicy : 1;
6806c3fb27SDimitry Andric bool HasFRMRoundModeOp : 1;
6906c3fb27SDimitry Andric bool IsTuple : 1;
70*0fca6ea1SDimitry Andric LLVM_PREFERRED_TYPE(PolicyScheme)
71bdd1243dSDimitry Andric uint8_t UnMaskedPolicyScheme : 2;
72*0fca6ea1SDimitry Andric LLVM_PREFERRED_TYPE(PolicyScheme)
73bdd1243dSDimitry Andric uint8_t MaskedPolicyScheme : 2;
74972a253aSDimitry Andric };
75972a253aSDimitry Andric
76972a253aSDimitry Andric // Compressed function signature table.
77972a253aSDimitry Andric class SemaSignatureTable {
78972a253aSDimitry Andric private:
79972a253aSDimitry Andric std::vector<PrototypeDescriptor> SignatureTable;
80972a253aSDimitry Andric
81972a253aSDimitry Andric void insert(ArrayRef<PrototypeDescriptor> Signature);
82972a253aSDimitry Andric
83972a253aSDimitry Andric public:
84972a253aSDimitry Andric static constexpr unsigned INVALID_INDEX = ~0U;
85972a253aSDimitry Andric
86972a253aSDimitry Andric // Create compressed signature table from SemaRecords.
87972a253aSDimitry Andric void init(ArrayRef<SemaRecord> SemaRecords);
88972a253aSDimitry Andric
89972a253aSDimitry Andric // Query the Signature, return INVALID_INDEX if not found.
90972a253aSDimitry Andric unsigned getIndex(ArrayRef<PrototypeDescriptor> Signature);
91972a253aSDimitry Andric
92972a253aSDimitry Andric /// Print signature table in RVVHeader Record to \p OS
93972a253aSDimitry Andric void print(raw_ostream &OS);
94972a253aSDimitry Andric };
95972a253aSDimitry Andric
96fe6060f1SDimitry Andric class RVVEmitter {
97fe6060f1SDimitry Andric private:
98fe6060f1SDimitry Andric RecordKeeper &Records;
99bdd1243dSDimitry Andric RVVTypeCache TypeCache;
100fe6060f1SDimitry Andric
101fe6060f1SDimitry Andric public:
RVVEmitter(RecordKeeper & R)102fe6060f1SDimitry Andric RVVEmitter(RecordKeeper &R) : Records(R) {}
103fe6060f1SDimitry Andric
104fe6060f1SDimitry Andric /// Emit riscv_vector.h
105fe6060f1SDimitry Andric void createHeader(raw_ostream &o);
106fe6060f1SDimitry Andric
107fe6060f1SDimitry Andric /// Emit all the __builtin prototypes and code needed by Sema.
108fe6060f1SDimitry Andric void createBuiltins(raw_ostream &o);
109fe6060f1SDimitry Andric
110fe6060f1SDimitry Andric /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
111fe6060f1SDimitry Andric void createCodeGen(raw_ostream &o);
112fe6060f1SDimitry Andric
113972a253aSDimitry Andric /// Emit all the information needed by SemaRISCVVectorLookup.cpp.
114972a253aSDimitry Andric /// We've large number of intrinsic function for RVV, creating a customized
115972a253aSDimitry Andric /// could speed up the compilation time.
116972a253aSDimitry Andric void createSema(raw_ostream &o);
117972a253aSDimitry Andric
118fe6060f1SDimitry Andric private:
119972a253aSDimitry Andric /// Create all intrinsics and add them to \p Out and SemaRecords.
120972a253aSDimitry Andric void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out,
121972a253aSDimitry Andric std::vector<SemaRecord> *SemaRecords = nullptr);
122972a253aSDimitry Andric /// Create all intrinsic records and SemaSignatureTable from SemaRecords.
123972a253aSDimitry Andric void createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out,
124972a253aSDimitry Andric SemaSignatureTable &SST,
125972a253aSDimitry Andric ArrayRef<SemaRecord> SemaRecords);
126972a253aSDimitry Andric
12781ad6265SDimitry Andric /// Print HeaderCode in RVVHeader Record to \p Out
12881ad6265SDimitry Andric void printHeaderCode(raw_ostream &OS);
129fe6060f1SDimitry Andric };
130fe6060f1SDimitry Andric
131fe6060f1SDimitry Andric } // namespace
132fe6060f1SDimitry Andric
ParseBasicType(char c)13381ad6265SDimitry Andric static BasicType ParseBasicType(char c) {
13481ad6265SDimitry Andric switch (c) {
135fe6060f1SDimitry Andric case 'c':
13681ad6265SDimitry Andric return BasicType::Int8;
137fe6060f1SDimitry Andric break;
138fe6060f1SDimitry Andric case 's':
13981ad6265SDimitry Andric return BasicType::Int16;
140fe6060f1SDimitry Andric break;
141fe6060f1SDimitry Andric case 'i':
14281ad6265SDimitry Andric return BasicType::Int32;
143fe6060f1SDimitry Andric break;
144fe6060f1SDimitry Andric case 'l':
14581ad6265SDimitry Andric return BasicType::Int64;
146fe6060f1SDimitry Andric break;
147fe6060f1SDimitry Andric case 'x':
14881ad6265SDimitry Andric return BasicType::Float16;
149fe6060f1SDimitry Andric break;
150fe6060f1SDimitry Andric case 'f':
15181ad6265SDimitry Andric return BasicType::Float32;
152fe6060f1SDimitry Andric break;
153fe6060f1SDimitry Andric case 'd':
15481ad6265SDimitry Andric return BasicType::Float64;
155fe6060f1SDimitry Andric break;
156647cbc5dSDimitry Andric case 'y':
1575f757f3fSDimitry Andric return BasicType::BFloat16;
1585f757f3fSDimitry Andric break;
159fe6060f1SDimitry Andric default:
16081ad6265SDimitry Andric return BasicType::Unknown;
161fe6060f1SDimitry Andric }
162fe6060f1SDimitry Andric }
163fe6060f1SDimitry Andric
getTupleVTM(unsigned NF)16406c3fb27SDimitry Andric static VectorTypeModifier getTupleVTM(unsigned NF) {
16506c3fb27SDimitry Andric assert(2 <= NF && NF <= 8 && "2 <= NF <= 8");
16606c3fb27SDimitry Andric return static_cast<VectorTypeModifier>(
16706c3fb27SDimitry Andric static_cast<uint8_t>(VectorTypeModifier::Tuple2) + (NF - 2));
16806c3fb27SDimitry Andric }
16906c3fb27SDimitry Andric
emitCodeGenSwitchBody(const RVVIntrinsic * RVVI,raw_ostream & OS)17081ad6265SDimitry Andric void emitCodeGenSwitchBody(const RVVIntrinsic *RVVI, raw_ostream &OS) {
17181ad6265SDimitry Andric if (!RVVI->getIRName().empty())
17281ad6265SDimitry Andric OS << " ID = Intrinsic::riscv_" + RVVI->getIRName() + ";\n";
17381ad6265SDimitry Andric if (RVVI->getNF() >= 2)
17481ad6265SDimitry Andric OS << " NF = " + utostr(RVVI->getNF()) + ";\n";
175bdd1243dSDimitry Andric
176bdd1243dSDimitry Andric OS << " PolicyAttrs = " << RVVI->getPolicyAttrsBits() << ";\n";
177bdd1243dSDimitry Andric
17881ad6265SDimitry Andric if (RVVI->hasManualCodegen()) {
179bdd1243dSDimitry Andric OS << "IsMasked = " << (RVVI->isMasked() ? "true" : "false") << ";\n";
18081ad6265SDimitry Andric OS << RVVI->getManualCodegen();
181fe6060f1SDimitry Andric OS << "break;\n";
182fe6060f1SDimitry Andric return;
183fe6060f1SDimitry Andric }
184fe6060f1SDimitry Andric
185753f127fSDimitry Andric for (const auto &I : enumerate(RVVI->getInputTypes())) {
186753f127fSDimitry Andric if (I.value()->isPointer()) {
187753f127fSDimitry Andric assert(RVVI->getIntrinsicTypes().front() == -1 &&
188753f127fSDimitry Andric "RVVI should be vector load intrinsic.");
189753f127fSDimitry Andric }
190753f127fSDimitry Andric }
191753f127fSDimitry Andric
19281ad6265SDimitry Andric if (RVVI->isMasked()) {
19381ad6265SDimitry Andric if (RVVI->hasVL()) {
194fe6060f1SDimitry Andric OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n";
19581ad6265SDimitry Andric if (RVVI->hasPolicyOperand())
196349cc55cSDimitry Andric OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(),"
197bdd1243dSDimitry Andric " PolicyAttrs));\n";
198bdd1243dSDimitry Andric if (RVVI->hasMaskedOffOperand() && RVVI->getPolicyAttrs().isTAMAPolicy())
199bdd1243dSDimitry Andric OS << " Ops.insert(Ops.begin(), "
200bdd1243dSDimitry Andric "llvm::PoisonValue::get(ResultType));\n";
201bdd1243dSDimitry Andric // Masked reduction cases.
202bdd1243dSDimitry Andric if (!RVVI->hasMaskedOffOperand() && RVVI->hasPassthruOperand() &&
203bdd1243dSDimitry Andric RVVI->getPolicyAttrs().isTAMAPolicy())
204bdd1243dSDimitry Andric OS << " Ops.insert(Ops.begin(), "
205bdd1243dSDimitry Andric "llvm::PoisonValue::get(ResultType));\n";
206fe6060f1SDimitry Andric } else {
207fe6060f1SDimitry Andric OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n";
208fe6060f1SDimitry Andric }
20981ad6265SDimitry Andric } else {
21081ad6265SDimitry Andric if (RVVI->hasPolicyOperand())
21181ad6265SDimitry Andric OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(), "
212bdd1243dSDimitry Andric "PolicyAttrs));\n";
213bdd1243dSDimitry Andric else if (RVVI->hasPassthruOperand() && RVVI->getPolicyAttrs().isTAPolicy())
214bdd1243dSDimitry Andric OS << " Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));\n";
215fe6060f1SDimitry Andric }
216fe6060f1SDimitry Andric
217fe6060f1SDimitry Andric OS << " IntrinsicTypes = {";
218fe6060f1SDimitry Andric ListSeparator LS;
21981ad6265SDimitry Andric for (const auto &Idx : RVVI->getIntrinsicTypes()) {
220fe6060f1SDimitry Andric if (Idx == -1)
221fe6060f1SDimitry Andric OS << LS << "ResultType";
222fe6060f1SDimitry Andric else
223fe6060f1SDimitry Andric OS << LS << "Ops[" << Idx << "]->getType()";
224fe6060f1SDimitry Andric }
225fe6060f1SDimitry Andric
226fe6060f1SDimitry Andric // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is
227fe6060f1SDimitry Andric // always last operand.
22881ad6265SDimitry Andric if (RVVI->hasVL())
229fe6060f1SDimitry Andric OS << ", Ops.back()->getType()";
230fe6060f1SDimitry Andric OS << "};\n";
231fe6060f1SDimitry Andric OS << " break;\n";
232fe6060f1SDimitry Andric }
233fe6060f1SDimitry Andric
234972a253aSDimitry Andric //===----------------------------------------------------------------------===//
235972a253aSDimitry Andric // SemaSignatureTable implementation
236972a253aSDimitry Andric //===----------------------------------------------------------------------===//
init(ArrayRef<SemaRecord> SemaRecords)237972a253aSDimitry Andric void SemaSignatureTable::init(ArrayRef<SemaRecord> SemaRecords) {
238972a253aSDimitry Andric // Sort signature entries by length, let longer signature insert first, to
239972a253aSDimitry Andric // make it more possible to reuse table entries, that can reduce ~10% table
240972a253aSDimitry Andric // size.
241972a253aSDimitry Andric struct Compare {
242972a253aSDimitry Andric bool operator()(const SmallVector<PrototypeDescriptor> &A,
243972a253aSDimitry Andric const SmallVector<PrototypeDescriptor> &B) const {
244972a253aSDimitry Andric if (A.size() != B.size())
245972a253aSDimitry Andric return A.size() > B.size();
246972a253aSDimitry Andric
247972a253aSDimitry Andric size_t Len = A.size();
248972a253aSDimitry Andric for (size_t i = 0; i < Len; ++i) {
249972a253aSDimitry Andric if (A[i] != B[i])
250972a253aSDimitry Andric return A[i] < B[i];
251fe6060f1SDimitry Andric }
252fe6060f1SDimitry Andric
253972a253aSDimitry Andric return false;
254fe6060f1SDimitry Andric }
255972a253aSDimitry Andric };
256972a253aSDimitry Andric
257972a253aSDimitry Andric std::set<SmallVector<PrototypeDescriptor>, Compare> Signatures;
258972a253aSDimitry Andric auto InsertToSignatureSet =
259972a253aSDimitry Andric [&](const SmallVector<PrototypeDescriptor> &Signature) {
260972a253aSDimitry Andric if (Signature.empty())
261972a253aSDimitry Andric return;
262972a253aSDimitry Andric
263972a253aSDimitry Andric Signatures.insert(Signature);
264972a253aSDimitry Andric };
265972a253aSDimitry Andric
266972a253aSDimitry Andric assert(!SemaRecords.empty());
267972a253aSDimitry Andric
2685f757f3fSDimitry Andric for (const SemaRecord &SR : SemaRecords) {
269972a253aSDimitry Andric InsertToSignatureSet(SR.Prototype);
270972a253aSDimitry Andric InsertToSignatureSet(SR.Suffix);
271972a253aSDimitry Andric InsertToSignatureSet(SR.OverloadedSuffix);
2725f757f3fSDimitry Andric }
273972a253aSDimitry Andric
2745f757f3fSDimitry Andric for (auto &Sig : Signatures)
2755f757f3fSDimitry Andric insert(Sig);
276972a253aSDimitry Andric }
277972a253aSDimitry Andric
insert(ArrayRef<PrototypeDescriptor> Signature)278972a253aSDimitry Andric void SemaSignatureTable::insert(ArrayRef<PrototypeDescriptor> Signature) {
279972a253aSDimitry Andric if (getIndex(Signature) != INVALID_INDEX)
280972a253aSDimitry Andric return;
281972a253aSDimitry Andric
282972a253aSDimitry Andric // Insert Signature into SignatureTable if not found in the table.
283972a253aSDimitry Andric SignatureTable.insert(SignatureTable.begin(), Signature.begin(),
284972a253aSDimitry Andric Signature.end());
285972a253aSDimitry Andric }
286972a253aSDimitry Andric
getIndex(ArrayRef<PrototypeDescriptor> Signature)287972a253aSDimitry Andric unsigned SemaSignatureTable::getIndex(ArrayRef<PrototypeDescriptor> Signature) {
288972a253aSDimitry Andric // Empty signature could be point into any index since there is length
289972a253aSDimitry Andric // field when we use, so just always point it to 0.
290972a253aSDimitry Andric if (Signature.empty())
291972a253aSDimitry Andric return 0;
292972a253aSDimitry Andric
293972a253aSDimitry Andric // Checking Signature already in table or not.
2945f757f3fSDimitry Andric if (Signature.size() <= SignatureTable.size()) {
295972a253aSDimitry Andric size_t Bound = SignatureTable.size() - Signature.size() + 1;
296972a253aSDimitry Andric for (size_t Index = 0; Index < Bound; ++Index) {
297972a253aSDimitry Andric if (equal(Signature.begin(), Signature.end(),
298972a253aSDimitry Andric SignatureTable.begin() + Index))
299972a253aSDimitry Andric return Index;
300972a253aSDimitry Andric }
301972a253aSDimitry Andric }
302972a253aSDimitry Andric
303972a253aSDimitry Andric return INVALID_INDEX;
304972a253aSDimitry Andric }
305972a253aSDimitry Andric
print(raw_ostream & OS)306972a253aSDimitry Andric void SemaSignatureTable::print(raw_ostream &OS) {
307972a253aSDimitry Andric for (const auto &Sig : SignatureTable)
308972a253aSDimitry Andric OS << "PrototypeDescriptor(" << static_cast<int>(Sig.PT) << ", "
309972a253aSDimitry Andric << static_cast<int>(Sig.VTM) << ", " << static_cast<int>(Sig.TM)
310972a253aSDimitry Andric << "),\n";
311fe6060f1SDimitry Andric }
312fe6060f1SDimitry Andric
313fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
314fe6060f1SDimitry Andric // RVVEmitter implementation
315fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
createHeader(raw_ostream & OS)316fe6060f1SDimitry Andric void RVVEmitter::createHeader(raw_ostream &OS) {
317fe6060f1SDimitry Andric
318fe6060f1SDimitry Andric OS << "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics "
319fe6060f1SDimitry Andric "-------------------===\n"
320fe6060f1SDimitry Andric " *\n"
321fe6060f1SDimitry Andric " *\n"
322fe6060f1SDimitry Andric " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
323fe6060f1SDimitry Andric "Exceptions.\n"
324fe6060f1SDimitry Andric " * See https://llvm.org/LICENSE.txt for license information.\n"
325fe6060f1SDimitry Andric " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
326fe6060f1SDimitry Andric " *\n"
327fe6060f1SDimitry Andric " *===-----------------------------------------------------------------"
328fe6060f1SDimitry Andric "------===\n"
329fe6060f1SDimitry Andric " */\n\n";
330fe6060f1SDimitry Andric
331fe6060f1SDimitry Andric OS << "#ifndef __RISCV_VECTOR_H\n";
332fe6060f1SDimitry Andric OS << "#define __RISCV_VECTOR_H\n\n";
333fe6060f1SDimitry Andric
334fe6060f1SDimitry Andric OS << "#include <stdint.h>\n";
335fe6060f1SDimitry Andric OS << "#include <stddef.h>\n\n";
336fe6060f1SDimitry Andric
337fe6060f1SDimitry Andric OS << "#ifdef __cplusplus\n";
338fe6060f1SDimitry Andric OS << "extern \"C\" {\n";
339fe6060f1SDimitry Andric OS << "#endif\n\n";
340fe6060f1SDimitry Andric
341972a253aSDimitry Andric OS << "#pragma clang riscv intrinsic vector\n\n";
342349cc55cSDimitry Andric
343972a253aSDimitry Andric printHeaderCode(OS);
344fe6060f1SDimitry Andric
345fe6060f1SDimitry Andric auto printType = [&](auto T) {
346fe6060f1SDimitry Andric OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr()
347fe6060f1SDimitry Andric << ";\n";
348fe6060f1SDimitry Andric };
349fe6060f1SDimitry Andric
350fe6060f1SDimitry Andric constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3};
351fe6060f1SDimitry Andric // Print RVV boolean types.
352fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) {
353bdd1243dSDimitry Andric auto T = TypeCache.computeType(BasicType::Int8, Log2LMUL,
35481ad6265SDimitry Andric PrototypeDescriptor::Mask);
35581ad6265SDimitry Andric if (T)
356bdd1243dSDimitry Andric printType(*T);
357fe6060f1SDimitry Andric }
358fe6060f1SDimitry Andric // Print RVV int/float types.
359fe6060f1SDimitry Andric for (char I : StringRef("csil")) {
36081ad6265SDimitry Andric BasicType BT = ParseBasicType(I);
361fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) {
362bdd1243dSDimitry Andric auto T = TypeCache.computeType(BT, Log2LMUL, PrototypeDescriptor::Vector);
36381ad6265SDimitry Andric if (T) {
364bdd1243dSDimitry Andric printType(*T);
365bdd1243dSDimitry Andric auto UT = TypeCache.computeType(
36681ad6265SDimitry Andric BT, Log2LMUL,
36781ad6265SDimitry Andric PrototypeDescriptor(BaseTypeModifier::Vector,
36881ad6265SDimitry Andric VectorTypeModifier::NoModifier,
36981ad6265SDimitry Andric TypeModifier::UnsignedInteger));
370bdd1243dSDimitry Andric printType(*UT);
371fe6060f1SDimitry Andric }
37206c3fb27SDimitry Andric for (int NF = 2; NF <= 8; ++NF) {
37306c3fb27SDimitry Andric auto TupleT = TypeCache.computeType(
37406c3fb27SDimitry Andric BT, Log2LMUL,
37506c3fb27SDimitry Andric PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF),
37606c3fb27SDimitry Andric TypeModifier::SignedInteger));
37706c3fb27SDimitry Andric auto TupleUT = TypeCache.computeType(
37806c3fb27SDimitry Andric BT, Log2LMUL,
37906c3fb27SDimitry Andric PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF),
38006c3fb27SDimitry Andric TypeModifier::UnsignedInteger));
38106c3fb27SDimitry Andric if (TupleT)
38206c3fb27SDimitry Andric printType(*TupleT);
38306c3fb27SDimitry Andric if (TupleUT)
38406c3fb27SDimitry Andric printType(*TupleUT);
385fe6060f1SDimitry Andric }
386fe6060f1SDimitry Andric }
387fe6060f1SDimitry Andric }
388fe6060f1SDimitry Andric
3895f757f3fSDimitry Andric for (BasicType BT : {BasicType::Float16, BasicType::Float32,
3905f757f3fSDimitry Andric BasicType::Float64, BasicType::BFloat16}) {
391fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) {
39206c3fb27SDimitry Andric auto T = TypeCache.computeType(BT, Log2LMUL, PrototypeDescriptor::Vector);
39381ad6265SDimitry Andric if (T)
394bdd1243dSDimitry Andric printType(*T);
39506c3fb27SDimitry Andric for (int NF = 2; NF <= 8; ++NF) {
39606c3fb27SDimitry Andric auto TupleT = TypeCache.computeType(
39706c3fb27SDimitry Andric BT, Log2LMUL,
39806c3fb27SDimitry Andric PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF),
3995f757f3fSDimitry Andric (BT == BasicType::BFloat16
4005f757f3fSDimitry Andric ? TypeModifier::BFloat
4015f757f3fSDimitry Andric : TypeModifier::Float)));
40206c3fb27SDimitry Andric if (TupleT)
40306c3fb27SDimitry Andric printType(*TupleT);
404fe6060f1SDimitry Andric }
405fe6060f1SDimitry Andric }
40606c3fb27SDimitry Andric }
407fe6060f1SDimitry Andric
408fe6060f1SDimitry Andric OS << "#define __riscv_v_intrinsic_overloading 1\n";
409fe6060f1SDimitry Andric
410fe6060f1SDimitry Andric OS << "\n#ifdef __cplusplus\n";
411fe6060f1SDimitry Andric OS << "}\n";
412349cc55cSDimitry Andric OS << "#endif // __cplusplus\n";
413fe6060f1SDimitry Andric OS << "#endif // __RISCV_VECTOR_H\n";
414fe6060f1SDimitry Andric }
415fe6060f1SDimitry Andric
createBuiltins(raw_ostream & OS)416fe6060f1SDimitry Andric void RVVEmitter::createBuiltins(raw_ostream &OS) {
417fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
418fe6060f1SDimitry Andric createRVVIntrinsics(Defs);
419fe6060f1SDimitry Andric
420349cc55cSDimitry Andric // Map to keep track of which builtin names have already been emitted.
421349cc55cSDimitry Andric StringMap<RVVIntrinsic *> BuiltinMap;
422349cc55cSDimitry Andric
423fe6060f1SDimitry Andric OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n";
424fe6060f1SDimitry Andric OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, "
42581ad6265SDimitry Andric "ATTRS, \"zve32x\")\n";
426fe6060f1SDimitry Andric OS << "#endif\n";
427fe6060f1SDimitry Andric for (auto &Def : Defs) {
428349cc55cSDimitry Andric auto P =
429349cc55cSDimitry Andric BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get()));
430349cc55cSDimitry Andric if (!P.second) {
43181ad6265SDimitry Andric // Verf that this would have produced the same builtin definition.
43281ad6265SDimitry Andric if (P.first->second->hasBuiltinAlias() != Def->hasBuiltinAlias())
433349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different hasAutoDef");
43481ad6265SDimitry Andric else if (!Def->hasBuiltinAlias() &&
43581ad6265SDimitry Andric P.first->second->getBuiltinTypeStr() != Def->getBuiltinTypeStr())
436349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different type string");
437349cc55cSDimitry Andric continue;
438349cc55cSDimitry Andric }
439349cc55cSDimitry Andric OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getBuiltinName() << ",\"";
44081ad6265SDimitry Andric if (!Def->hasBuiltinAlias())
441349cc55cSDimitry Andric OS << Def->getBuiltinTypeStr();
442349cc55cSDimitry Andric OS << "\", \"n\")\n";
443fe6060f1SDimitry Andric }
444fe6060f1SDimitry Andric OS << "#undef RISCVV_BUILTIN\n";
445fe6060f1SDimitry Andric }
446fe6060f1SDimitry Andric
createCodeGen(raw_ostream & OS)447fe6060f1SDimitry Andric void RVVEmitter::createCodeGen(raw_ostream &OS) {
448fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
449fe6060f1SDimitry Andric createRVVIntrinsics(Defs);
450fe6060f1SDimitry Andric // IR name could be empty, use the stable sort preserves the relative order.
451349cc55cSDimitry Andric llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A,
452fe6060f1SDimitry Andric const std::unique_ptr<RVVIntrinsic> &B) {
453bdd1243dSDimitry Andric if (A->getIRName() == B->getIRName())
454bdd1243dSDimitry Andric return (A->getPolicyAttrs() < B->getPolicyAttrs());
455bdd1243dSDimitry Andric return (A->getIRName() < B->getIRName());
456fe6060f1SDimitry Andric });
457349cc55cSDimitry Andric
458349cc55cSDimitry Andric // Map to keep track of which builtin names have already been emitted.
459349cc55cSDimitry Andric StringMap<RVVIntrinsic *> BuiltinMap;
460349cc55cSDimitry Andric
461bdd1243dSDimitry Andric // Print switch body when the ir name, ManualCodegen or policy changes from
462bdd1243dSDimitry Andric // previous iteration.
463fe6060f1SDimitry Andric RVVIntrinsic *PrevDef = Defs.begin()->get();
464fe6060f1SDimitry Andric for (auto &Def : Defs) {
465fe6060f1SDimitry Andric StringRef CurIRName = Def->getIRName();
466fe6060f1SDimitry Andric if (CurIRName != PrevDef->getIRName() ||
467bdd1243dSDimitry Andric (Def->getManualCodegen() != PrevDef->getManualCodegen()) ||
468bdd1243dSDimitry Andric (Def->getPolicyAttrs() != PrevDef->getPolicyAttrs())) {
46981ad6265SDimitry Andric emitCodeGenSwitchBody(PrevDef, OS);
470fe6060f1SDimitry Andric }
471fe6060f1SDimitry Andric PrevDef = Def.get();
472349cc55cSDimitry Andric
473349cc55cSDimitry Andric auto P =
474349cc55cSDimitry Andric BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get()));
475349cc55cSDimitry Andric if (P.second) {
476349cc55cSDimitry Andric OS << "case RISCVVector::BI__builtin_rvv_" << Def->getBuiltinName()
477349cc55cSDimitry Andric << ":\n";
478349cc55cSDimitry Andric continue;
479349cc55cSDimitry Andric }
480349cc55cSDimitry Andric
481349cc55cSDimitry Andric if (P.first->second->getIRName() != Def->getIRName())
482349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different IRName");
483349cc55cSDimitry Andric else if (P.first->second->getManualCodegen() != Def->getManualCodegen())
484349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different ManualCodegen");
48581ad6265SDimitry Andric else if (P.first->second->isMasked() != Def->isMasked())
48681ad6265SDimitry Andric PrintFatalError("Builtin with same name has different isMasked");
487349cc55cSDimitry Andric else if (P.first->second->hasVL() != Def->hasVL())
48881ad6265SDimitry Andric PrintFatalError("Builtin with same name has different hasVL");
48981ad6265SDimitry Andric else if (P.first->second->getPolicyScheme() != Def->getPolicyScheme())
49081ad6265SDimitry Andric PrintFatalError("Builtin with same name has different getPolicyScheme");
491349cc55cSDimitry Andric else if (P.first->second->getIntrinsicTypes() != Def->getIntrinsicTypes())
492349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different IntrinsicTypes");
493fe6060f1SDimitry Andric }
49481ad6265SDimitry Andric emitCodeGenSwitchBody(Defs.back().get(), OS);
495fe6060f1SDimitry Andric OS << "\n";
496fe6060f1SDimitry Andric }
497fe6060f1SDimitry Andric
createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> & Out,std::vector<SemaRecord> * SemaRecords)498fe6060f1SDimitry Andric void RVVEmitter::createRVVIntrinsics(
499972a253aSDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> &Out,
500972a253aSDimitry Andric std::vector<SemaRecord> *SemaRecords) {
501fe6060f1SDimitry Andric std::vector<Record *> RV = Records.getAllDerivedDefinitions("RVVBuiltin");
502fe6060f1SDimitry Andric for (auto *R : RV) {
503fe6060f1SDimitry Andric StringRef Name = R->getValueAsString("Name");
504fe6060f1SDimitry Andric StringRef SuffixProto = R->getValueAsString("Suffix");
50581ad6265SDimitry Andric StringRef OverloadedName = R->getValueAsString("OverloadedName");
50681ad6265SDimitry Andric StringRef OverloadedSuffixProto = R->getValueAsString("OverloadedSuffix");
507fe6060f1SDimitry Andric StringRef Prototypes = R->getValueAsString("Prototype");
508fe6060f1SDimitry Andric StringRef TypeRange = R->getValueAsString("TypeRange");
50981ad6265SDimitry Andric bool HasMasked = R->getValueAsBit("HasMasked");
510fe6060f1SDimitry Andric bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand");
511fe6060f1SDimitry Andric bool HasVL = R->getValueAsBit("HasVL");
512972a253aSDimitry Andric Record *MPSRecord = R->getValueAsDef("MaskedPolicyScheme");
513972a253aSDimitry Andric auto MaskedPolicyScheme =
514972a253aSDimitry Andric static_cast<PolicyScheme>(MPSRecord->getValueAsInt("Value"));
515972a253aSDimitry Andric Record *UMPSRecord = R->getValueAsDef("UnMaskedPolicyScheme");
516972a253aSDimitry Andric auto UnMaskedPolicyScheme =
517972a253aSDimitry Andric static_cast<PolicyScheme>(UMPSRecord->getValueAsInt("Value"));
518fe6060f1SDimitry Andric std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL");
519bdd1243dSDimitry Andric bool HasTailPolicy = R->getValueAsBit("HasTailPolicy");
520bdd1243dSDimitry Andric bool HasMaskPolicy = R->getValueAsBit("HasMaskPolicy");
521bdd1243dSDimitry Andric bool SupportOverloading = R->getValueAsBit("SupportOverloading");
52281ad6265SDimitry Andric bool HasBuiltinAlias = R->getValueAsBit("HasBuiltinAlias");
523fe6060f1SDimitry Andric StringRef ManualCodegen = R->getValueAsString("ManualCodegen");
524fe6060f1SDimitry Andric std::vector<int64_t> IntrinsicTypes =
525fe6060f1SDimitry Andric R->getValueAsListOfInts("IntrinsicTypes");
52604eeddc0SDimitry Andric std::vector<StringRef> RequiredFeatures =
52704eeddc0SDimitry Andric R->getValueAsListOfStrings("RequiredFeatures");
528fe6060f1SDimitry Andric StringRef IRName = R->getValueAsString("IRName");
52981ad6265SDimitry Andric StringRef MaskedIRName = R->getValueAsString("MaskedIRName");
530fe6060f1SDimitry Andric unsigned NF = R->getValueAsInt("NF");
53106c3fb27SDimitry Andric bool IsTuple = R->getValueAsBit("IsTuple");
53206c3fb27SDimitry Andric bool HasFRMRoundModeOp = R->getValueAsBit("HasFRMRoundModeOp");
533fe6060f1SDimitry Andric
5341ac55f4cSDimitry Andric const Policy DefaultPolicy;
535bdd1243dSDimitry Andric SmallVector<Policy> SupportedUnMaskedPolicies =
5361ac55f4cSDimitry Andric RVVIntrinsic::getSupportedUnMaskedPolicies();
537bdd1243dSDimitry Andric SmallVector<Policy> SupportedMaskedPolicies =
538bdd1243dSDimitry Andric RVVIntrinsic::getSupportedMaskedPolicies(HasTailPolicy, HasMaskPolicy);
539bdd1243dSDimitry Andric
540fe6060f1SDimitry Andric // Parse prototype and create a list of primitive type with transformers
54181ad6265SDimitry Andric // (operand) in Prototype. Prototype[0] is output operand.
542972a253aSDimitry Andric SmallVector<PrototypeDescriptor> BasicPrototype =
543972a253aSDimitry Andric parsePrototypes(Prototypes);
54481ad6265SDimitry Andric
54581ad6265SDimitry Andric SmallVector<PrototypeDescriptor> SuffixDesc = parsePrototypes(SuffixProto);
54681ad6265SDimitry Andric SmallVector<PrototypeDescriptor> OverloadedSuffixDesc =
54781ad6265SDimitry Andric parsePrototypes(OverloadedSuffixProto);
548fe6060f1SDimitry Andric
549fe6060f1SDimitry Andric // Compute Builtin types
550972a253aSDimitry Andric auto Prototype = RVVIntrinsic::computeBuiltinTypes(
551bdd1243dSDimitry Andric BasicPrototype, /*IsMasked=*/false,
552bdd1243dSDimitry Andric /*HasMaskedOffOperand=*/false, HasVL, NF, UnMaskedPolicyScheme,
55306c3fb27SDimitry Andric DefaultPolicy, IsTuple);
55406c3fb27SDimitry Andric llvm::SmallVector<PrototypeDescriptor> MaskedPrototype;
55506c3fb27SDimitry Andric if (HasMasked)
55606c3fb27SDimitry Andric MaskedPrototype = RVVIntrinsic::computeBuiltinTypes(
557bdd1243dSDimitry Andric BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, NF,
55806c3fb27SDimitry Andric MaskedPolicyScheme, DefaultPolicy, IsTuple);
559fe6060f1SDimitry Andric
560fe6060f1SDimitry Andric // Create Intrinsics for each type and LMUL.
561fe6060f1SDimitry Andric for (char I : TypeRange) {
562fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULList) {
56381ad6265SDimitry Andric BasicType BT = ParseBasicType(I);
564bdd1243dSDimitry Andric std::optional<RVVTypes> Types =
565bdd1243dSDimitry Andric TypeCache.computeTypes(BT, Log2LMUL, NF, Prototype);
566fe6060f1SDimitry Andric // Ignored to create new intrinsic if there are any illegal types.
56781ad6265SDimitry Andric if (!Types)
568fe6060f1SDimitry Andric continue;
569fe6060f1SDimitry Andric
570bdd1243dSDimitry Andric auto SuffixStr =
571bdd1243dSDimitry Andric RVVIntrinsic::getSuffixStr(TypeCache, BT, Log2LMUL, SuffixDesc);
572bdd1243dSDimitry Andric auto OverloadedSuffixStr = RVVIntrinsic::getSuffixStr(
573bdd1243dSDimitry Andric TypeCache, BT, Log2LMUL, OverloadedSuffixDesc);
57481ad6265SDimitry Andric // Create a unmasked intrinsic
575fe6060f1SDimitry Andric Out.push_back(std::make_unique<RVVIntrinsic>(
57681ad6265SDimitry Andric Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName,
57781ad6265SDimitry Andric /*IsMasked=*/false, /*HasMaskedOffOperand=*/false, HasVL,
578bdd1243dSDimitry Andric UnMaskedPolicyScheme, SupportOverloading, HasBuiltinAlias,
579*0fca6ea1SDimitry Andric ManualCodegen, *Types, IntrinsicTypes, NF, DefaultPolicy,
580*0fca6ea1SDimitry Andric HasFRMRoundModeOp));
581bdd1243dSDimitry Andric if (UnMaskedPolicyScheme != PolicyScheme::SchemeNone)
582bdd1243dSDimitry Andric for (auto P : SupportedUnMaskedPolicies) {
583bdd1243dSDimitry Andric SmallVector<PrototypeDescriptor> PolicyPrototype =
584bdd1243dSDimitry Andric RVVIntrinsic::computeBuiltinTypes(
585bdd1243dSDimitry Andric BasicPrototype, /*IsMasked=*/false,
586bdd1243dSDimitry Andric /*HasMaskedOffOperand=*/false, HasVL, NF,
58706c3fb27SDimitry Andric UnMaskedPolicyScheme, P, IsTuple);
588bdd1243dSDimitry Andric std::optional<RVVTypes> PolicyTypes =
589bdd1243dSDimitry Andric TypeCache.computeTypes(BT, Log2LMUL, NF, PolicyPrototype);
590bdd1243dSDimitry Andric Out.push_back(std::make_unique<RVVIntrinsic>(
591bdd1243dSDimitry Andric Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName,
592bdd1243dSDimitry Andric /*IsMask=*/false, /*HasMaskedOffOperand=*/false, HasVL,
593bdd1243dSDimitry Andric UnMaskedPolicyScheme, SupportOverloading, HasBuiltinAlias,
594*0fca6ea1SDimitry Andric ManualCodegen, *PolicyTypes, IntrinsicTypes, NF, P,
595*0fca6ea1SDimitry Andric HasFRMRoundModeOp));
596bdd1243dSDimitry Andric }
597bdd1243dSDimitry Andric if (!HasMasked)
598bdd1243dSDimitry Andric continue;
59981ad6265SDimitry Andric // Create a masked intrinsic
600bdd1243dSDimitry Andric std::optional<RVVTypes> MaskTypes =
601bdd1243dSDimitry Andric TypeCache.computeTypes(BT, Log2LMUL, NF, MaskedPrototype);
602bdd1243dSDimitry Andric Out.push_back(std::make_unique<RVVIntrinsic>(
603bdd1243dSDimitry Andric Name, SuffixStr, OverloadedName, OverloadedSuffixStr, MaskedIRName,
604bdd1243dSDimitry Andric /*IsMasked=*/true, HasMaskedOffOperand, HasVL, MaskedPolicyScheme,
605bdd1243dSDimitry Andric SupportOverloading, HasBuiltinAlias, ManualCodegen, *MaskTypes,
606*0fca6ea1SDimitry Andric IntrinsicTypes, NF, DefaultPolicy, HasFRMRoundModeOp));
607bdd1243dSDimitry Andric if (MaskedPolicyScheme == PolicyScheme::SchemeNone)
608bdd1243dSDimitry Andric continue;
609bdd1243dSDimitry Andric for (auto P : SupportedMaskedPolicies) {
610bdd1243dSDimitry Andric SmallVector<PrototypeDescriptor> PolicyPrototype =
611bdd1243dSDimitry Andric RVVIntrinsic::computeBuiltinTypes(
612bdd1243dSDimitry Andric BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL,
61306c3fb27SDimitry Andric NF, MaskedPolicyScheme, P, IsTuple);
614bdd1243dSDimitry Andric std::optional<RVVTypes> PolicyTypes =
615bdd1243dSDimitry Andric TypeCache.computeTypes(BT, Log2LMUL, NF, PolicyPrototype);
616fe6060f1SDimitry Andric Out.push_back(std::make_unique<RVVIntrinsic>(
61781ad6265SDimitry Andric Name, SuffixStr, OverloadedName, OverloadedSuffixStr,
618bdd1243dSDimitry Andric MaskedIRName, /*IsMasked=*/true, HasMaskedOffOperand, HasVL,
619bdd1243dSDimitry Andric MaskedPolicyScheme, SupportOverloading, HasBuiltinAlias,
620*0fca6ea1SDimitry Andric ManualCodegen, *PolicyTypes, IntrinsicTypes, NF, P,
621*0fca6ea1SDimitry Andric HasFRMRoundModeOp));
622fe6060f1SDimitry Andric }
623bdd1243dSDimitry Andric } // End for Log2LMULList
624bdd1243dSDimitry Andric } // End for TypeRange
625972a253aSDimitry Andric
626972a253aSDimitry Andric // We don't emit vsetvli and vsetvlimax for SemaRecord.
627972a253aSDimitry Andric // They are written in riscv_vector.td and will emit those marco define in
628972a253aSDimitry Andric // riscv_vector.h
629972a253aSDimitry Andric if (Name == "vsetvli" || Name == "vsetvlimax")
630972a253aSDimitry Andric continue;
631972a253aSDimitry Andric
632972a253aSDimitry Andric if (!SemaRecords)
633972a253aSDimitry Andric continue;
634972a253aSDimitry Andric
635972a253aSDimitry Andric // Create SemaRecord
636972a253aSDimitry Andric SemaRecord SR;
637972a253aSDimitry Andric SR.Name = Name.str();
638972a253aSDimitry Andric SR.OverloadedName = OverloadedName.str();
639972a253aSDimitry Andric BasicType TypeRangeMask = BasicType::Unknown;
640972a253aSDimitry Andric for (char I : TypeRange)
641972a253aSDimitry Andric TypeRangeMask |= ParseBasicType(I);
642972a253aSDimitry Andric
643972a253aSDimitry Andric SR.TypeRangeMask = static_cast<unsigned>(TypeRangeMask);
644972a253aSDimitry Andric
645972a253aSDimitry Andric unsigned Log2LMULMask = 0;
646972a253aSDimitry Andric for (int Log2LMUL : Log2LMULList)
647972a253aSDimitry Andric Log2LMULMask |= 1 << (Log2LMUL + 3);
648972a253aSDimitry Andric
649972a253aSDimitry Andric SR.Log2LMULMask = Log2LMULMask;
650972a253aSDimitry Andric
651972a253aSDimitry Andric SR.RequiredExtensions = 0;
652972a253aSDimitry Andric for (auto RequiredFeature : RequiredFeatures) {
653cb14a3feSDimitry Andric RVVRequire RequireExt =
654cb14a3feSDimitry Andric StringSwitch<RVVRequire>(RequiredFeature)
655972a253aSDimitry Andric .Case("RV64", RVV_REQ_RV64)
6567a6dacacSDimitry Andric .Case("Zvfhmin", RVV_REQ_Zvfhmin)
65706c3fb27SDimitry Andric .Case("Xsfvcp", RVV_REQ_Xsfvcp)
6585f757f3fSDimitry Andric .Case("Xsfvfnrclipxfqf", RVV_REQ_Xsfvfnrclipxfqf)
6595f757f3fSDimitry Andric .Case("Xsfvfwmaccqqq", RVV_REQ_Xsfvfwmaccqqq)
6605f757f3fSDimitry Andric .Case("Xsfvqmaccdod", RVV_REQ_Xsfvqmaccdod)
6615f757f3fSDimitry Andric .Case("Xsfvqmaccqoq", RVV_REQ_Xsfvqmaccqoq)
6625f757f3fSDimitry Andric .Case("Zvbb", RVV_REQ_Zvbb)
6635f757f3fSDimitry Andric .Case("Zvbc", RVV_REQ_Zvbc)
6645f757f3fSDimitry Andric .Case("Zvkb", RVV_REQ_Zvkb)
6655f757f3fSDimitry Andric .Case("Zvkg", RVV_REQ_Zvkg)
6665f757f3fSDimitry Andric .Case("Zvkned", RVV_REQ_Zvkned)
6675f757f3fSDimitry Andric .Case("Zvknha", RVV_REQ_Zvknha)
6685f757f3fSDimitry Andric .Case("Zvknhb", RVV_REQ_Zvknhb)
6695f757f3fSDimitry Andric .Case("Zvksed", RVV_REQ_Zvksed)
6705f757f3fSDimitry Andric .Case("Zvksh", RVV_REQ_Zvksh)
671*0fca6ea1SDimitry Andric .Case("Zvfbfwma", RVV_REQ_Zvfbfwma)
672*0fca6ea1SDimitry Andric .Case("Zvfbfmin", RVV_REQ_Zvfbfmin)
673cb14a3feSDimitry Andric .Case("Experimental", RVV_REQ_Experimental)
674972a253aSDimitry Andric .Default(RVV_REQ_None);
675972a253aSDimitry Andric assert(RequireExt != RVV_REQ_None && "Unrecognized required feature?");
676972a253aSDimitry Andric SR.RequiredExtensions |= RequireExt;
677972a253aSDimitry Andric }
678972a253aSDimitry Andric
679972a253aSDimitry Andric SR.NF = NF;
680972a253aSDimitry Andric SR.HasMasked = HasMasked;
681972a253aSDimitry Andric SR.HasVL = HasVL;
682972a253aSDimitry Andric SR.HasMaskedOffOperand = HasMaskedOffOperand;
683bdd1243dSDimitry Andric SR.HasTailPolicy = HasTailPolicy;
684bdd1243dSDimitry Andric SR.HasMaskPolicy = HasMaskPolicy;
685bdd1243dSDimitry Andric SR.UnMaskedPolicyScheme = static_cast<uint8_t>(UnMaskedPolicyScheme);
686bdd1243dSDimitry Andric SR.MaskedPolicyScheme = static_cast<uint8_t>(MaskedPolicyScheme);
687972a253aSDimitry Andric SR.Prototype = std::move(BasicPrototype);
688972a253aSDimitry Andric SR.Suffix = parsePrototypes(SuffixProto);
689972a253aSDimitry Andric SR.OverloadedSuffix = parsePrototypes(OverloadedSuffixProto);
69006c3fb27SDimitry Andric SR.IsTuple = IsTuple;
69106c3fb27SDimitry Andric SR.HasFRMRoundModeOp = HasFRMRoundModeOp;
692972a253aSDimitry Andric
693972a253aSDimitry Andric SemaRecords->push_back(SR);
694fe6060f1SDimitry Andric }
695fe6060f1SDimitry Andric }
696fe6060f1SDimitry Andric
printHeaderCode(raw_ostream & OS)69781ad6265SDimitry Andric void RVVEmitter::printHeaderCode(raw_ostream &OS) {
698349cc55cSDimitry Andric std::vector<Record *> RVVHeaders =
699349cc55cSDimitry Andric Records.getAllDerivedDefinitions("RVVHeader");
700349cc55cSDimitry Andric for (auto *R : RVVHeaders) {
701349cc55cSDimitry Andric StringRef HeaderCodeStr = R->getValueAsString("HeaderCode");
702349cc55cSDimitry Andric OS << HeaderCodeStr.str();
703349cc55cSDimitry Andric }
704349cc55cSDimitry Andric }
705349cc55cSDimitry Andric
createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> & Out,SemaSignatureTable & SST,ArrayRef<SemaRecord> SemaRecords)706972a253aSDimitry Andric void RVVEmitter::createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out,
707972a253aSDimitry Andric SemaSignatureTable &SST,
708972a253aSDimitry Andric ArrayRef<SemaRecord> SemaRecords) {
709972a253aSDimitry Andric SST.init(SemaRecords);
710972a253aSDimitry Andric
711972a253aSDimitry Andric for (const auto &SR : SemaRecords) {
712972a253aSDimitry Andric Out.emplace_back(RVVIntrinsicRecord());
713972a253aSDimitry Andric RVVIntrinsicRecord &R = Out.back();
714972a253aSDimitry Andric R.Name = SR.Name.c_str();
715972a253aSDimitry Andric R.OverloadedName = SR.OverloadedName.c_str();
716972a253aSDimitry Andric R.PrototypeIndex = SST.getIndex(SR.Prototype);
717972a253aSDimitry Andric R.SuffixIndex = SST.getIndex(SR.Suffix);
718972a253aSDimitry Andric R.OverloadedSuffixIndex = SST.getIndex(SR.OverloadedSuffix);
719972a253aSDimitry Andric R.PrototypeLength = SR.Prototype.size();
720972a253aSDimitry Andric R.SuffixLength = SR.Suffix.size();
721972a253aSDimitry Andric R.OverloadedSuffixSize = SR.OverloadedSuffix.size();
722972a253aSDimitry Andric R.RequiredExtensions = SR.RequiredExtensions;
723972a253aSDimitry Andric R.TypeRangeMask = SR.TypeRangeMask;
724972a253aSDimitry Andric R.Log2LMULMask = SR.Log2LMULMask;
725972a253aSDimitry Andric R.NF = SR.NF;
726972a253aSDimitry Andric R.HasMasked = SR.HasMasked;
727972a253aSDimitry Andric R.HasVL = SR.HasVL;
728972a253aSDimitry Andric R.HasMaskedOffOperand = SR.HasMaskedOffOperand;
729bdd1243dSDimitry Andric R.HasTailPolicy = SR.HasTailPolicy;
730bdd1243dSDimitry Andric R.HasMaskPolicy = SR.HasMaskPolicy;
731bdd1243dSDimitry Andric R.UnMaskedPolicyScheme = SR.UnMaskedPolicyScheme;
732bdd1243dSDimitry Andric R.MaskedPolicyScheme = SR.MaskedPolicyScheme;
73306c3fb27SDimitry Andric R.IsTuple = SR.IsTuple;
73406c3fb27SDimitry Andric R.HasFRMRoundModeOp = SR.HasFRMRoundModeOp;
735972a253aSDimitry Andric
736972a253aSDimitry Andric assert(R.PrototypeIndex !=
737972a253aSDimitry Andric static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX));
738972a253aSDimitry Andric assert(R.SuffixIndex !=
739972a253aSDimitry Andric static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX));
740972a253aSDimitry Andric assert(R.OverloadedSuffixIndex !=
741972a253aSDimitry Andric static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX));
742fe6060f1SDimitry Andric }
743fe6060f1SDimitry Andric }
744fe6060f1SDimitry Andric
createSema(raw_ostream & OS)745972a253aSDimitry Andric void RVVEmitter::createSema(raw_ostream &OS) {
746972a253aSDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
747972a253aSDimitry Andric std::vector<RVVIntrinsicRecord> RVVIntrinsicRecords;
748972a253aSDimitry Andric SemaSignatureTable SST;
749972a253aSDimitry Andric std::vector<SemaRecord> SemaRecords;
750972a253aSDimitry Andric
751972a253aSDimitry Andric createRVVIntrinsics(Defs, &SemaRecords);
752972a253aSDimitry Andric
753972a253aSDimitry Andric createRVVIntrinsicRecords(RVVIntrinsicRecords, SST, SemaRecords);
754972a253aSDimitry Andric
755972a253aSDimitry Andric // Emit signature table for SemaRISCVVectorLookup.cpp.
756972a253aSDimitry Andric OS << "#ifdef DECL_SIGNATURE_TABLE\n";
757972a253aSDimitry Andric SST.print(OS);
758972a253aSDimitry Andric OS << "#endif\n";
759972a253aSDimitry Andric
760972a253aSDimitry Andric // Emit RVVIntrinsicRecords for SemaRISCVVectorLookup.cpp.
761972a253aSDimitry Andric OS << "#ifdef DECL_INTRINSIC_RECORDS\n";
762972a253aSDimitry Andric for (const RVVIntrinsicRecord &Record : RVVIntrinsicRecords)
763972a253aSDimitry Andric OS << Record;
764972a253aSDimitry Andric OS << "#endif\n";
765fe6060f1SDimitry Andric }
766fe6060f1SDimitry Andric
767fe6060f1SDimitry Andric namespace clang {
EmitRVVHeader(RecordKeeper & Records,raw_ostream & OS)768fe6060f1SDimitry Andric void EmitRVVHeader(RecordKeeper &Records, raw_ostream &OS) {
769fe6060f1SDimitry Andric RVVEmitter(Records).createHeader(OS);
770fe6060f1SDimitry Andric }
771fe6060f1SDimitry Andric
EmitRVVBuiltins(RecordKeeper & Records,raw_ostream & OS)772fe6060f1SDimitry Andric void EmitRVVBuiltins(RecordKeeper &Records, raw_ostream &OS) {
773fe6060f1SDimitry Andric RVVEmitter(Records).createBuiltins(OS);
774fe6060f1SDimitry Andric }
775fe6060f1SDimitry Andric
EmitRVVBuiltinCG(RecordKeeper & Records,raw_ostream & OS)776fe6060f1SDimitry Andric void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
777fe6060f1SDimitry Andric RVVEmitter(Records).createCodeGen(OS);
778fe6060f1SDimitry Andric }
779fe6060f1SDimitry Andric
EmitRVVBuiltinSema(RecordKeeper & Records,raw_ostream & OS)780972a253aSDimitry Andric void EmitRVVBuiltinSema(RecordKeeper &Records, raw_ostream &OS) {
781972a253aSDimitry Andric RVVEmitter(Records).createSema(OS);
782972a253aSDimitry Andric }
783972a253aSDimitry Andric
784fe6060f1SDimitry Andric } // End namespace clang
785