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