1 //===- RISCVVEmitter.cpp - Generate riscv_vector.h for use with clang -----===//
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
7 //===----------------------------------------------------------------------===//
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.
13 // See also the documentation in include/clang/Basic/riscv_vector.td.
15 //===----------------------------------------------------------------------===//
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"
31 using namespace clang::RISCV
;
35 // Intrinsic name, e.g. vadd_vv
38 // Overloaded intrinsic name, could be empty if can be computed from Name
40 std::string OverloadedName
;
42 // Supported type, mask of BasicType.
43 unsigned TypeRangeMask
;
46 unsigned Log2LMULMask
;
48 // Required extensions for this intrinsic.
49 uint32_t RequiredExtensions
;
51 // Prototype for this intrinsic.
52 SmallVector
<PrototypeDescriptor
> Prototype
;
54 // Suffix of intrinsic name.
55 SmallVector
<PrototypeDescriptor
> Suffix
;
57 // Suffix of overloaded intrinsic name.
58 SmallVector
<PrototypeDescriptor
> OverloadedSuffix
;
60 // Number of field, large than 1 if it's segment load/store.
65 bool HasMaskedOffOperand
:1;
66 bool HasTailPolicy
: 1;
67 bool HasMaskPolicy
: 1;
68 bool HasFRMRoundModeOp
: 1;
70 uint8_t UnMaskedPolicyScheme
: 2;
71 uint8_t MaskedPolicyScheme
: 2;
74 // Compressed function signature table.
75 class SemaSignatureTable
{
77 std::vector
<PrototypeDescriptor
> SignatureTable
;
79 void insert(ArrayRef
<PrototypeDescriptor
> Signature
);
82 static constexpr unsigned INVALID_INDEX
= ~0U;
84 // Create compressed signature table from SemaRecords.
85 void init(ArrayRef
<SemaRecord
> SemaRecords
);
87 // Query the Signature, return INVALID_INDEX if not found.
88 unsigned getIndex(ArrayRef
<PrototypeDescriptor
> Signature
);
90 /// Print signature table in RVVHeader Record to \p OS
91 void print(raw_ostream
&OS
);
96 RecordKeeper
&Records
;
97 RVVTypeCache TypeCache
;
100 RVVEmitter(RecordKeeper
&R
) : Records(R
) {}
102 /// Emit riscv_vector.h
103 void createHeader(raw_ostream
&o
);
105 /// Emit all the __builtin prototypes and code needed by Sema.
106 void createBuiltins(raw_ostream
&o
);
108 /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
109 void createCodeGen(raw_ostream
&o
);
111 /// Emit all the information needed by SemaRISCVVectorLookup.cpp.
112 /// We've large number of intrinsic function for RVV, creating a customized
113 /// could speed up the compilation time.
114 void createSema(raw_ostream
&o
);
117 /// Create all intrinsics and add them to \p Out and SemaRecords.
118 void createRVVIntrinsics(std::vector
<std::unique_ptr
<RVVIntrinsic
>> &Out
,
119 std::vector
<SemaRecord
> *SemaRecords
= nullptr);
120 /// Create all intrinsic records and SemaSignatureTable from SemaRecords.
121 void createRVVIntrinsicRecords(std::vector
<RVVIntrinsicRecord
> &Out
,
122 SemaSignatureTable
&SST
,
123 ArrayRef
<SemaRecord
> SemaRecords
);
125 /// Print HeaderCode in RVVHeader Record to \p Out
126 void printHeaderCode(raw_ostream
&OS
);
131 static BasicType
ParseBasicType(char c
) {
134 return BasicType::Int8
;
137 return BasicType::Int16
;
140 return BasicType::Int32
;
143 return BasicType::Int64
;
146 return BasicType::Float16
;
149 return BasicType::Float32
;
152 return BasicType::Float64
;
155 return BasicType::BFloat16
;
158 return BasicType::Unknown
;
162 static VectorTypeModifier
getTupleVTM(unsigned NF
) {
163 assert(2 <= NF
&& NF
<= 8 && "2 <= NF <= 8");
164 return static_cast<VectorTypeModifier
>(
165 static_cast<uint8_t>(VectorTypeModifier::Tuple2
) + (NF
- 2));
168 void emitCodeGenSwitchBody(const RVVIntrinsic
*RVVI
, raw_ostream
&OS
) {
169 if (!RVVI
->getIRName().empty())
170 OS
<< " ID = Intrinsic::riscv_" + RVVI
->getIRName() + ";\n";
171 if (RVVI
->getNF() >= 2)
172 OS
<< " NF = " + utostr(RVVI
->getNF()) + ";\n";
174 OS
<< " PolicyAttrs = " << RVVI
->getPolicyAttrsBits() << ";\n";
176 if (RVVI
->hasManualCodegen()) {
177 OS
<< "IsMasked = " << (RVVI
->isMasked() ? "true" : "false") << ";\n";
178 OS
<< RVVI
->getManualCodegen();
183 for (const auto &I
: enumerate(RVVI
->getInputTypes())) {
184 if (I
.value()->isPointer()) {
185 assert(RVVI
->getIntrinsicTypes().front() == -1 &&
186 "RVVI should be vector load intrinsic.");
190 if (RVVI
->isMasked()) {
192 OS
<< " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n";
193 if (RVVI
->hasPolicyOperand())
194 OS
<< " Ops.push_back(ConstantInt::get(Ops.back()->getType(),"
196 if (RVVI
->hasMaskedOffOperand() && RVVI
->getPolicyAttrs().isTAMAPolicy())
197 OS
<< " Ops.insert(Ops.begin(), "
198 "llvm::PoisonValue::get(ResultType));\n";
199 // Masked reduction cases.
200 if (!RVVI
->hasMaskedOffOperand() && RVVI
->hasPassthruOperand() &&
201 RVVI
->getPolicyAttrs().isTAMAPolicy())
202 OS
<< " Ops.insert(Ops.begin(), "
203 "llvm::PoisonValue::get(ResultType));\n";
205 OS
<< " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n";
208 if (RVVI
->hasPolicyOperand())
209 OS
<< " Ops.push_back(ConstantInt::get(Ops.back()->getType(), "
211 else if (RVVI
->hasPassthruOperand() && RVVI
->getPolicyAttrs().isTAPolicy())
212 OS
<< " Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));\n";
215 OS
<< " IntrinsicTypes = {";
217 for (const auto &Idx
: RVVI
->getIntrinsicTypes()) {
219 OS
<< LS
<< "ResultType";
221 OS
<< LS
<< "Ops[" << Idx
<< "]->getType()";
224 // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is
225 // always last operand.
227 OS
<< ", Ops.back()->getType()";
232 //===----------------------------------------------------------------------===//
233 // SemaSignatureTable implementation
234 //===----------------------------------------------------------------------===//
235 void SemaSignatureTable::init(ArrayRef
<SemaRecord
> SemaRecords
) {
236 // Sort signature entries by length, let longer signature insert first, to
237 // make it more possible to reuse table entries, that can reduce ~10% table
240 bool operator()(const SmallVector
<PrototypeDescriptor
> &A
,
241 const SmallVector
<PrototypeDescriptor
> &B
) const {
242 if (A
.size() != B
.size())
243 return A
.size() > B
.size();
245 size_t Len
= A
.size();
246 for (size_t i
= 0; i
< Len
; ++i
) {
255 std::set
<SmallVector
<PrototypeDescriptor
>, Compare
> Signatures
;
256 auto InsertToSignatureSet
=
257 [&](const SmallVector
<PrototypeDescriptor
> &Signature
) {
258 if (Signature
.empty())
261 Signatures
.insert(Signature
);
264 assert(!SemaRecords
.empty());
266 for (const SemaRecord
&SR
: SemaRecords
) {
267 InsertToSignatureSet(SR
.Prototype
);
268 InsertToSignatureSet(SR
.Suffix
);
269 InsertToSignatureSet(SR
.OverloadedSuffix
);
272 for (auto &Sig
: Signatures
)
276 void SemaSignatureTable::insert(ArrayRef
<PrototypeDescriptor
> Signature
) {
277 if (getIndex(Signature
) != INVALID_INDEX
)
280 // Insert Signature into SignatureTable if not found in the table.
281 SignatureTable
.insert(SignatureTable
.begin(), Signature
.begin(),
285 unsigned SemaSignatureTable::getIndex(ArrayRef
<PrototypeDescriptor
> Signature
) {
286 // Empty signature could be point into any index since there is length
287 // field when we use, so just always point it to 0.
288 if (Signature
.empty())
291 // Checking Signature already in table or not.
292 if (Signature
.size() <= SignatureTable
.size()) {
293 size_t Bound
= SignatureTable
.size() - Signature
.size() + 1;
294 for (size_t Index
= 0; Index
< Bound
; ++Index
) {
295 if (equal(Signature
.begin(), Signature
.end(),
296 SignatureTable
.begin() + Index
))
301 return INVALID_INDEX
;
304 void SemaSignatureTable::print(raw_ostream
&OS
) {
305 for (const auto &Sig
: SignatureTable
)
306 OS
<< "PrototypeDescriptor(" << static_cast<int>(Sig
.PT
) << ", "
307 << static_cast<int>(Sig
.VTM
) << ", " << static_cast<int>(Sig
.TM
)
311 //===----------------------------------------------------------------------===//
312 // RVVEmitter implementation
313 //===----------------------------------------------------------------------===//
314 void RVVEmitter::createHeader(raw_ostream
&OS
) {
316 OS
<< "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics "
317 "-------------------===\n"
320 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
322 " * See https://llvm.org/LICENSE.txt for license information.\n"
323 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
325 " *===-----------------------------------------------------------------"
329 OS
<< "#ifndef __RISCV_VECTOR_H\n";
330 OS
<< "#define __RISCV_VECTOR_H\n\n";
332 OS
<< "#include <stdint.h>\n";
333 OS
<< "#include <stddef.h>\n\n";
335 OS
<< "#ifndef __riscv_vector\n";
336 OS
<< "#error \"Vector intrinsics require the vector extension.\"\n";
339 OS
<< "#ifdef __cplusplus\n";
340 OS
<< "extern \"C\" {\n";
343 OS
<< "#pragma clang riscv intrinsic vector\n\n";
347 auto printType
= [&](auto T
) {
348 OS
<< "typedef " << T
->getClangBuiltinStr() << " " << T
->getTypeStr()
352 constexpr int Log2LMULs
[] = {-3, -2, -1, 0, 1, 2, 3};
353 // Print RVV boolean types.
354 for (int Log2LMUL
: Log2LMULs
) {
355 auto T
= TypeCache
.computeType(BasicType::Int8
, Log2LMUL
,
356 PrototypeDescriptor::Mask
);
360 // Print RVV int/float types.
361 for (char I
: StringRef("csil")) {
362 BasicType BT
= ParseBasicType(I
);
363 for (int Log2LMUL
: Log2LMULs
) {
364 auto T
= TypeCache
.computeType(BT
, Log2LMUL
, PrototypeDescriptor::Vector
);
367 auto UT
= TypeCache
.computeType(
369 PrototypeDescriptor(BaseTypeModifier::Vector
,
370 VectorTypeModifier::NoModifier
,
371 TypeModifier::UnsignedInteger
));
374 for (int NF
= 2; NF
<= 8; ++NF
) {
375 auto TupleT
= TypeCache
.computeType(
377 PrototypeDescriptor(BaseTypeModifier::Vector
, getTupleVTM(NF
),
378 TypeModifier::SignedInteger
));
379 auto TupleUT
= TypeCache
.computeType(
381 PrototypeDescriptor(BaseTypeModifier::Vector
, getTupleVTM(NF
),
382 TypeModifier::UnsignedInteger
));
391 for (BasicType BT
: {BasicType::Float16
, BasicType::Float32
,
392 BasicType::Float64
, BasicType::BFloat16
}) {
393 for (int Log2LMUL
: Log2LMULs
) {
394 auto T
= TypeCache
.computeType(BT
, Log2LMUL
, PrototypeDescriptor::Vector
);
397 for (int NF
= 2; NF
<= 8; ++NF
) {
398 auto TupleT
= TypeCache
.computeType(
400 PrototypeDescriptor(BaseTypeModifier::Vector
, getTupleVTM(NF
),
401 (BT
== BasicType::BFloat16
402 ? TypeModifier::BFloat
403 : TypeModifier::Float
)));
410 OS
<< "#define __riscv_v_intrinsic_overloading 1\n";
412 OS
<< "\n#ifdef __cplusplus\n";
414 OS
<< "#endif // __cplusplus\n";
415 OS
<< "#endif // __RISCV_VECTOR_H\n";
418 void RVVEmitter::createBuiltins(raw_ostream
&OS
) {
419 std::vector
<std::unique_ptr
<RVVIntrinsic
>> Defs
;
420 createRVVIntrinsics(Defs
);
422 // Map to keep track of which builtin names have already been emitted.
423 StringMap
<RVVIntrinsic
*> BuiltinMap
;
425 OS
<< "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n";
426 OS
<< "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, "
427 "ATTRS, \"zve32x\")\n";
429 for (auto &Def
: Defs
) {
431 BuiltinMap
.insert(std::make_pair(Def
->getBuiltinName(), Def
.get()));
433 // Verf that this would have produced the same builtin definition.
434 if (P
.first
->second
->hasBuiltinAlias() != Def
->hasBuiltinAlias())
435 PrintFatalError("Builtin with same name has different hasAutoDef");
436 else if (!Def
->hasBuiltinAlias() &&
437 P
.first
->second
->getBuiltinTypeStr() != Def
->getBuiltinTypeStr())
438 PrintFatalError("Builtin with same name has different type string");
441 OS
<< "RISCVV_BUILTIN(__builtin_rvv_" << Def
->getBuiltinName() << ",\"";
442 if (!Def
->hasBuiltinAlias())
443 OS
<< Def
->getBuiltinTypeStr();
444 OS
<< "\", \"n\")\n";
446 OS
<< "#undef RISCVV_BUILTIN\n";
449 void RVVEmitter::createCodeGen(raw_ostream
&OS
) {
450 std::vector
<std::unique_ptr
<RVVIntrinsic
>> Defs
;
451 createRVVIntrinsics(Defs
);
452 // IR name could be empty, use the stable sort preserves the relative order.
453 llvm::stable_sort(Defs
, [](const std::unique_ptr
<RVVIntrinsic
> &A
,
454 const std::unique_ptr
<RVVIntrinsic
> &B
) {
455 if (A
->getIRName() == B
->getIRName())
456 return (A
->getPolicyAttrs() < B
->getPolicyAttrs());
457 return (A
->getIRName() < B
->getIRName());
460 // Map to keep track of which builtin names have already been emitted.
461 StringMap
<RVVIntrinsic
*> BuiltinMap
;
463 // Print switch body when the ir name, ManualCodegen or policy changes from
464 // previous iteration.
465 RVVIntrinsic
*PrevDef
= Defs
.begin()->get();
466 for (auto &Def
: Defs
) {
467 StringRef CurIRName
= Def
->getIRName();
468 if (CurIRName
!= PrevDef
->getIRName() ||
469 (Def
->getManualCodegen() != PrevDef
->getManualCodegen()) ||
470 (Def
->getPolicyAttrs() != PrevDef
->getPolicyAttrs())) {
471 emitCodeGenSwitchBody(PrevDef
, OS
);
476 BuiltinMap
.insert(std::make_pair(Def
->getBuiltinName(), Def
.get()));
478 OS
<< "case RISCVVector::BI__builtin_rvv_" << Def
->getBuiltinName()
483 if (P
.first
->second
->getIRName() != Def
->getIRName())
484 PrintFatalError("Builtin with same name has different IRName");
485 else if (P
.first
->second
->getManualCodegen() != Def
->getManualCodegen())
486 PrintFatalError("Builtin with same name has different ManualCodegen");
487 else if (P
.first
->second
->isMasked() != Def
->isMasked())
488 PrintFatalError("Builtin with same name has different isMasked");
489 else if (P
.first
->second
->hasVL() != Def
->hasVL())
490 PrintFatalError("Builtin with same name has different hasVL");
491 else if (P
.first
->second
->getPolicyScheme() != Def
->getPolicyScheme())
492 PrintFatalError("Builtin with same name has different getPolicyScheme");
493 else if (P
.first
->second
->getIntrinsicTypes() != Def
->getIntrinsicTypes())
494 PrintFatalError("Builtin with same name has different IntrinsicTypes");
496 emitCodeGenSwitchBody(Defs
.back().get(), OS
);
500 void RVVEmitter::createRVVIntrinsics(
501 std::vector
<std::unique_ptr
<RVVIntrinsic
>> &Out
,
502 std::vector
<SemaRecord
> *SemaRecords
) {
503 std::vector
<Record
*> RV
= Records
.getAllDerivedDefinitions("RVVBuiltin");
505 StringRef Name
= R
->getValueAsString("Name");
506 StringRef SuffixProto
= R
->getValueAsString("Suffix");
507 StringRef OverloadedName
= R
->getValueAsString("OverloadedName");
508 StringRef OverloadedSuffixProto
= R
->getValueAsString("OverloadedSuffix");
509 StringRef Prototypes
= R
->getValueAsString("Prototype");
510 StringRef TypeRange
= R
->getValueAsString("TypeRange");
511 bool HasMasked
= R
->getValueAsBit("HasMasked");
512 bool HasMaskedOffOperand
= R
->getValueAsBit("HasMaskedOffOperand");
513 bool HasVL
= R
->getValueAsBit("HasVL");
514 Record
*MPSRecord
= R
->getValueAsDef("MaskedPolicyScheme");
515 auto MaskedPolicyScheme
=
516 static_cast<PolicyScheme
>(MPSRecord
->getValueAsInt("Value"));
517 Record
*UMPSRecord
= R
->getValueAsDef("UnMaskedPolicyScheme");
518 auto UnMaskedPolicyScheme
=
519 static_cast<PolicyScheme
>(UMPSRecord
->getValueAsInt("Value"));
520 std::vector
<int64_t> Log2LMULList
= R
->getValueAsListOfInts("Log2LMUL");
521 bool HasTailPolicy
= R
->getValueAsBit("HasTailPolicy");
522 bool HasMaskPolicy
= R
->getValueAsBit("HasMaskPolicy");
523 bool SupportOverloading
= R
->getValueAsBit("SupportOverloading");
524 bool HasBuiltinAlias
= R
->getValueAsBit("HasBuiltinAlias");
525 StringRef ManualCodegen
= R
->getValueAsString("ManualCodegen");
526 std::vector
<int64_t> IntrinsicTypes
=
527 R
->getValueAsListOfInts("IntrinsicTypes");
528 std::vector
<StringRef
> RequiredFeatures
=
529 R
->getValueAsListOfStrings("RequiredFeatures");
530 StringRef IRName
= R
->getValueAsString("IRName");
531 StringRef MaskedIRName
= R
->getValueAsString("MaskedIRName");
532 unsigned NF
= R
->getValueAsInt("NF");
533 bool IsTuple
= R
->getValueAsBit("IsTuple");
534 bool HasFRMRoundModeOp
= R
->getValueAsBit("HasFRMRoundModeOp");
536 const Policy DefaultPolicy
;
537 SmallVector
<Policy
> SupportedUnMaskedPolicies
=
538 RVVIntrinsic::getSupportedUnMaskedPolicies();
539 SmallVector
<Policy
> SupportedMaskedPolicies
=
540 RVVIntrinsic::getSupportedMaskedPolicies(HasTailPolicy
, HasMaskPolicy
);
542 // Parse prototype and create a list of primitive type with transformers
543 // (operand) in Prototype. Prototype[0] is output operand.
544 SmallVector
<PrototypeDescriptor
> BasicPrototype
=
545 parsePrototypes(Prototypes
);
547 SmallVector
<PrototypeDescriptor
> SuffixDesc
= parsePrototypes(SuffixProto
);
548 SmallVector
<PrototypeDescriptor
> OverloadedSuffixDesc
=
549 parsePrototypes(OverloadedSuffixProto
);
551 // Compute Builtin types
552 auto Prototype
= RVVIntrinsic::computeBuiltinTypes(
553 BasicPrototype
, /*IsMasked=*/false,
554 /*HasMaskedOffOperand=*/false, HasVL
, NF
, UnMaskedPolicyScheme
,
555 DefaultPolicy
, IsTuple
);
556 llvm::SmallVector
<PrototypeDescriptor
> MaskedPrototype
;
558 MaskedPrototype
= RVVIntrinsic::computeBuiltinTypes(
559 BasicPrototype
, /*IsMasked=*/true, HasMaskedOffOperand
, HasVL
, NF
,
560 MaskedPolicyScheme
, DefaultPolicy
, IsTuple
);
562 // Create Intrinsics for each type and LMUL.
563 for (char I
: TypeRange
) {
564 for (int Log2LMUL
: Log2LMULList
) {
565 BasicType BT
= ParseBasicType(I
);
566 std::optional
<RVVTypes
> Types
=
567 TypeCache
.computeTypes(BT
, Log2LMUL
, NF
, Prototype
);
568 // Ignored to create new intrinsic if there are any illegal types.
573 RVVIntrinsic::getSuffixStr(TypeCache
, BT
, Log2LMUL
, SuffixDesc
);
574 auto OverloadedSuffixStr
= RVVIntrinsic::getSuffixStr(
575 TypeCache
, BT
, Log2LMUL
, OverloadedSuffixDesc
);
576 // Create a unmasked intrinsic
577 Out
.push_back(std::make_unique
<RVVIntrinsic
>(
578 Name
, SuffixStr
, OverloadedName
, OverloadedSuffixStr
, IRName
,
579 /*IsMasked=*/false, /*HasMaskedOffOperand=*/false, HasVL
,
580 UnMaskedPolicyScheme
, SupportOverloading
, HasBuiltinAlias
,
581 ManualCodegen
, *Types
, IntrinsicTypes
, RequiredFeatures
, NF
,
582 DefaultPolicy
, HasFRMRoundModeOp
));
583 if (UnMaskedPolicyScheme
!= PolicyScheme::SchemeNone
)
584 for (auto P
: SupportedUnMaskedPolicies
) {
585 SmallVector
<PrototypeDescriptor
> PolicyPrototype
=
586 RVVIntrinsic::computeBuiltinTypes(
587 BasicPrototype
, /*IsMasked=*/false,
588 /*HasMaskedOffOperand=*/false, HasVL
, NF
,
589 UnMaskedPolicyScheme
, P
, IsTuple
);
590 std::optional
<RVVTypes
> PolicyTypes
=
591 TypeCache
.computeTypes(BT
, Log2LMUL
, NF
, PolicyPrototype
);
592 Out
.push_back(std::make_unique
<RVVIntrinsic
>(
593 Name
, SuffixStr
, OverloadedName
, OverloadedSuffixStr
, IRName
,
594 /*IsMask=*/false, /*HasMaskedOffOperand=*/false, HasVL
,
595 UnMaskedPolicyScheme
, SupportOverloading
, HasBuiltinAlias
,
596 ManualCodegen
, *PolicyTypes
, IntrinsicTypes
, RequiredFeatures
,
597 NF
, P
, HasFRMRoundModeOp
));
601 // Create a masked intrinsic
602 std::optional
<RVVTypes
> MaskTypes
=
603 TypeCache
.computeTypes(BT
, Log2LMUL
, NF
, MaskedPrototype
);
604 Out
.push_back(std::make_unique
<RVVIntrinsic
>(
605 Name
, SuffixStr
, OverloadedName
, OverloadedSuffixStr
, MaskedIRName
,
606 /*IsMasked=*/true, HasMaskedOffOperand
, HasVL
, MaskedPolicyScheme
,
607 SupportOverloading
, HasBuiltinAlias
, ManualCodegen
, *MaskTypes
,
608 IntrinsicTypes
, RequiredFeatures
, NF
, DefaultPolicy
,
610 if (MaskedPolicyScheme
== PolicyScheme::SchemeNone
)
612 for (auto P
: SupportedMaskedPolicies
) {
613 SmallVector
<PrototypeDescriptor
> PolicyPrototype
=
614 RVVIntrinsic::computeBuiltinTypes(
615 BasicPrototype
, /*IsMasked=*/true, HasMaskedOffOperand
, HasVL
,
616 NF
, MaskedPolicyScheme
, P
, IsTuple
);
617 std::optional
<RVVTypes
> PolicyTypes
=
618 TypeCache
.computeTypes(BT
, Log2LMUL
, NF
, PolicyPrototype
);
619 Out
.push_back(std::make_unique
<RVVIntrinsic
>(
620 Name
, SuffixStr
, OverloadedName
, OverloadedSuffixStr
,
621 MaskedIRName
, /*IsMasked=*/true, HasMaskedOffOperand
, HasVL
,
622 MaskedPolicyScheme
, SupportOverloading
, HasBuiltinAlias
,
623 ManualCodegen
, *PolicyTypes
, IntrinsicTypes
, RequiredFeatures
, NF
,
624 P
, HasFRMRoundModeOp
));
626 } // End for Log2LMULList
627 } // End for TypeRange
629 // We don't emit vsetvli and vsetvlimax for SemaRecord.
630 // They are written in riscv_vector.td and will emit those marco define in
632 if (Name
== "vsetvli" || Name
== "vsetvlimax")
640 SR
.Name
= Name
.str();
641 SR
.OverloadedName
= OverloadedName
.str();
642 BasicType TypeRangeMask
= BasicType::Unknown
;
643 for (char I
: TypeRange
)
644 TypeRangeMask
|= ParseBasicType(I
);
646 SR
.TypeRangeMask
= static_cast<unsigned>(TypeRangeMask
);
648 unsigned Log2LMULMask
= 0;
649 for (int Log2LMUL
: Log2LMULList
)
650 Log2LMULMask
|= 1 << (Log2LMUL
+ 3);
652 SR
.Log2LMULMask
= Log2LMULMask
;
654 SR
.RequiredExtensions
= 0;
655 for (auto RequiredFeature
: RequiredFeatures
) {
656 RVVRequire RequireExt
=
657 StringSwitch
<RVVRequire
>(RequiredFeature
)
658 .Case("RV64", RVV_REQ_RV64
)
659 .Case("ZvfhminOrZvfh", RVV_REQ_ZvfhminOrZvfh
)
660 .Case("Xsfvcp", RVV_REQ_Xsfvcp
)
661 .Case("Xsfvfnrclipxfqf", RVV_REQ_Xsfvfnrclipxfqf
)
662 .Case("Xsfvfwmaccqqq", RVV_REQ_Xsfvfwmaccqqq
)
663 .Case("Xsfvqmaccdod", RVV_REQ_Xsfvqmaccdod
)
664 .Case("Xsfvqmaccqoq", RVV_REQ_Xsfvqmaccqoq
)
665 .Case("Zvbb", RVV_REQ_Zvbb
)
666 .Case("Zvbc", RVV_REQ_Zvbc
)
667 .Case("Zvkb", RVV_REQ_Zvkb
)
668 .Case("Zvkg", RVV_REQ_Zvkg
)
669 .Case("Zvkned", RVV_REQ_Zvkned
)
670 .Case("Zvknha", RVV_REQ_Zvknha
)
671 .Case("Zvknhb", RVV_REQ_Zvknhb
)
672 .Case("Zvksed", RVV_REQ_Zvksed
)
673 .Case("Zvksh", RVV_REQ_Zvksh
)
674 .Case("Experimental", RVV_REQ_Experimental
)
675 .Default(RVV_REQ_None
);
676 assert(RequireExt
!= RVV_REQ_None
&& "Unrecognized required feature?");
677 SR
.RequiredExtensions
|= RequireExt
;
681 SR
.HasMasked
= HasMasked
;
683 SR
.HasMaskedOffOperand
= HasMaskedOffOperand
;
684 SR
.HasTailPolicy
= HasTailPolicy
;
685 SR
.HasMaskPolicy
= HasMaskPolicy
;
686 SR
.UnMaskedPolicyScheme
= static_cast<uint8_t>(UnMaskedPolicyScheme
);
687 SR
.MaskedPolicyScheme
= static_cast<uint8_t>(MaskedPolicyScheme
);
688 SR
.Prototype
= std::move(BasicPrototype
);
689 SR
.Suffix
= parsePrototypes(SuffixProto
);
690 SR
.OverloadedSuffix
= parsePrototypes(OverloadedSuffixProto
);
691 SR
.IsTuple
= IsTuple
;
692 SR
.HasFRMRoundModeOp
= HasFRMRoundModeOp
;
694 SemaRecords
->push_back(SR
);
698 void RVVEmitter::printHeaderCode(raw_ostream
&OS
) {
699 std::vector
<Record
*> RVVHeaders
=
700 Records
.getAllDerivedDefinitions("RVVHeader");
701 for (auto *R
: RVVHeaders
) {
702 StringRef HeaderCodeStr
= R
->getValueAsString("HeaderCode");
703 OS
<< HeaderCodeStr
.str();
707 void RVVEmitter::createRVVIntrinsicRecords(std::vector
<RVVIntrinsicRecord
> &Out
,
708 SemaSignatureTable
&SST
,
709 ArrayRef
<SemaRecord
> SemaRecords
) {
710 SST
.init(SemaRecords
);
712 for (const auto &SR
: SemaRecords
) {
713 Out
.emplace_back(RVVIntrinsicRecord());
714 RVVIntrinsicRecord
&R
= Out
.back();
715 R
.Name
= SR
.Name
.c_str();
716 R
.OverloadedName
= SR
.OverloadedName
.c_str();
717 R
.PrototypeIndex
= SST
.getIndex(SR
.Prototype
);
718 R
.SuffixIndex
= SST
.getIndex(SR
.Suffix
);
719 R
.OverloadedSuffixIndex
= SST
.getIndex(SR
.OverloadedSuffix
);
720 R
.PrototypeLength
= SR
.Prototype
.size();
721 R
.SuffixLength
= SR
.Suffix
.size();
722 R
.OverloadedSuffixSize
= SR
.OverloadedSuffix
.size();
723 R
.RequiredExtensions
= SR
.RequiredExtensions
;
724 R
.TypeRangeMask
= SR
.TypeRangeMask
;
725 R
.Log2LMULMask
= SR
.Log2LMULMask
;
727 R
.HasMasked
= SR
.HasMasked
;
729 R
.HasMaskedOffOperand
= SR
.HasMaskedOffOperand
;
730 R
.HasTailPolicy
= SR
.HasTailPolicy
;
731 R
.HasMaskPolicy
= SR
.HasMaskPolicy
;
732 R
.UnMaskedPolicyScheme
= SR
.UnMaskedPolicyScheme
;
733 R
.MaskedPolicyScheme
= SR
.MaskedPolicyScheme
;
734 R
.IsTuple
= SR
.IsTuple
;
735 R
.HasFRMRoundModeOp
= SR
.HasFRMRoundModeOp
;
737 assert(R
.PrototypeIndex
!=
738 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX
));
739 assert(R
.SuffixIndex
!=
740 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX
));
741 assert(R
.OverloadedSuffixIndex
!=
742 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX
));
746 void RVVEmitter::createSema(raw_ostream
&OS
) {
747 std::vector
<std::unique_ptr
<RVVIntrinsic
>> Defs
;
748 std::vector
<RVVIntrinsicRecord
> RVVIntrinsicRecords
;
749 SemaSignatureTable SST
;
750 std::vector
<SemaRecord
> SemaRecords
;
752 createRVVIntrinsics(Defs
, &SemaRecords
);
754 createRVVIntrinsicRecords(RVVIntrinsicRecords
, SST
, SemaRecords
);
756 // Emit signature table for SemaRISCVVectorLookup.cpp.
757 OS
<< "#ifdef DECL_SIGNATURE_TABLE\n";
761 // Emit RVVIntrinsicRecords for SemaRISCVVectorLookup.cpp.
762 OS
<< "#ifdef DECL_INTRINSIC_RECORDS\n";
763 for (const RVVIntrinsicRecord
&Record
: RVVIntrinsicRecords
)
769 void EmitRVVHeader(RecordKeeper
&Records
, raw_ostream
&OS
) {
770 RVVEmitter(Records
).createHeader(OS
);
773 void EmitRVVBuiltins(RecordKeeper
&Records
, raw_ostream
&OS
) {
774 RVVEmitter(Records
).createBuiltins(OS
);
777 void EmitRVVBuiltinCG(RecordKeeper
&Records
, raw_ostream
&OS
) {
778 RVVEmitter(Records
).createCodeGen(OS
);
781 void EmitRVVBuiltinSema(RecordKeeper
&Records
, raw_ostream
&OS
) {
782 RVVEmitter(Records
).createSema(OS
);
785 } // End namespace clang