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 unsigned 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
;
156 return BasicType::Unknown
;
160 static VectorTypeModifier
getTupleVTM(unsigned NF
) {
161 assert(2 <= NF
&& NF
<= 8 && "2 <= NF <= 8");
162 return static_cast<VectorTypeModifier
>(
163 static_cast<uint8_t>(VectorTypeModifier::Tuple2
) + (NF
- 2));
166 void emitCodeGenSwitchBody(const RVVIntrinsic
*RVVI
, raw_ostream
&OS
) {
167 if (!RVVI
->getIRName().empty())
168 OS
<< " ID = Intrinsic::riscv_" + RVVI
->getIRName() + ";\n";
169 if (RVVI
->getNF() >= 2)
170 OS
<< " NF = " + utostr(RVVI
->getNF()) + ";\n";
172 OS
<< " PolicyAttrs = " << RVVI
->getPolicyAttrsBits() << ";\n";
174 if (RVVI
->hasManualCodegen()) {
175 OS
<< "IsMasked = " << (RVVI
->isMasked() ? "true" : "false") << ";\n";
176 OS
<< RVVI
->getManualCodegen();
181 // Cast pointer operand of vector load intrinsic.
182 for (const auto &I
: enumerate(RVVI
->getInputTypes())) {
183 if (I
.value()->isPointer()) {
184 assert(RVVI
->getIntrinsicTypes().front() == -1 &&
185 "RVVI should be vector load intrinsic.");
186 OS
<< " Ops[" << I
.index() << "] = Builder.CreateBitCast(Ops[";
187 OS
<< I
.index() << "], ResultType->getPointerTo());\n";
191 if (RVVI
->isMasked()) {
193 OS
<< " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n";
194 if (RVVI
->hasPolicyOperand())
195 OS
<< " Ops.push_back(ConstantInt::get(Ops.back()->getType(),"
197 if (RVVI
->hasMaskedOffOperand() && RVVI
->getPolicyAttrs().isTAMAPolicy())
198 OS
<< " Ops.insert(Ops.begin(), "
199 "llvm::PoisonValue::get(ResultType));\n";
200 // Masked reduction cases.
201 if (!RVVI
->hasMaskedOffOperand() && RVVI
->hasPassthruOperand() &&
202 RVVI
->getPolicyAttrs().isTAMAPolicy())
203 OS
<< " Ops.insert(Ops.begin(), "
204 "llvm::PoisonValue::get(ResultType));\n";
206 OS
<< " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n";
209 if (RVVI
->hasPolicyOperand())
210 OS
<< " Ops.push_back(ConstantInt::get(Ops.back()->getType(), "
212 else if (RVVI
->hasPassthruOperand() && RVVI
->getPolicyAttrs().isTAPolicy())
213 OS
<< " Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));\n";
216 OS
<< " IntrinsicTypes = {";
218 for (const auto &Idx
: RVVI
->getIntrinsicTypes()) {
220 OS
<< LS
<< "ResultType";
222 OS
<< LS
<< "Ops[" << Idx
<< "]->getType()";
225 // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is
226 // always last operand.
228 OS
<< ", Ops.back()->getType()";
233 //===----------------------------------------------------------------------===//
234 // SemaSignatureTable implementation
235 //===----------------------------------------------------------------------===//
236 void SemaSignatureTable::init(ArrayRef
<SemaRecord
> SemaRecords
) {
237 // Sort signature entries by length, let longer signature insert first, to
238 // make it more possible to reuse table entries, that can reduce ~10% table
241 bool operator()(const SmallVector
<PrototypeDescriptor
> &A
,
242 const SmallVector
<PrototypeDescriptor
> &B
) const {
243 if (A
.size() != B
.size())
244 return A
.size() > B
.size();
246 size_t Len
= A
.size();
247 for (size_t i
= 0; i
< Len
; ++i
) {
256 std::set
<SmallVector
<PrototypeDescriptor
>, Compare
> Signatures
;
257 auto InsertToSignatureSet
=
258 [&](const SmallVector
<PrototypeDescriptor
> &Signature
) {
259 if (Signature
.empty())
262 Signatures
.insert(Signature
);
265 assert(!SemaRecords
.empty());
267 for (const SemaRecord
&SR
: SemaRecords
) {
268 InsertToSignatureSet(SR
.Prototype
);
269 InsertToSignatureSet(SR
.Suffix
);
270 InsertToSignatureSet(SR
.OverloadedSuffix
);
273 for (auto &Sig
: Signatures
)
277 void SemaSignatureTable::insert(ArrayRef
<PrototypeDescriptor
> Signature
) {
278 if (getIndex(Signature
) != INVALID_INDEX
)
281 // Insert Signature into SignatureTable if not found in the table.
282 SignatureTable
.insert(SignatureTable
.begin(), Signature
.begin(),
286 unsigned SemaSignatureTable::getIndex(ArrayRef
<PrototypeDescriptor
> Signature
) {
287 // Empty signature could be point into any index since there is length
288 // field when we use, so just always point it to 0.
289 if (Signature
.empty())
292 // Checking Signature already in table or not.
293 if (Signature
.size() <= SignatureTable
.size()) {
294 size_t Bound
= SignatureTable
.size() - Signature
.size() + 1;
295 for (size_t Index
= 0; Index
< Bound
; ++Index
) {
296 if (equal(Signature
.begin(), Signature
.end(),
297 SignatureTable
.begin() + Index
))
302 return INVALID_INDEX
;
305 void SemaSignatureTable::print(raw_ostream
&OS
) {
306 for (const auto &Sig
: SignatureTable
)
307 OS
<< "PrototypeDescriptor(" << static_cast<int>(Sig
.PT
) << ", "
308 << static_cast<int>(Sig
.VTM
) << ", " << static_cast<int>(Sig
.TM
)
312 //===----------------------------------------------------------------------===//
313 // RVVEmitter implementation
314 //===----------------------------------------------------------------------===//
315 void RVVEmitter::createHeader(raw_ostream
&OS
) {
317 OS
<< "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics "
318 "-------------------===\n"
321 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
323 " * See https://llvm.org/LICENSE.txt for license information.\n"
324 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
326 " *===-----------------------------------------------------------------"
330 OS
<< "#ifndef __RISCV_VECTOR_H\n";
331 OS
<< "#define __RISCV_VECTOR_H\n\n";
333 OS
<< "#include <stdint.h>\n";
334 OS
<< "#include <stddef.h>\n\n";
336 OS
<< "#ifndef __riscv_vector\n";
337 OS
<< "#error \"Vector intrinsics require the vector extension.\"\n";
340 OS
<< "#ifdef __cplusplus\n";
341 OS
<< "extern \"C\" {\n";
344 OS
<< "#pragma clang riscv intrinsic vector\n\n";
348 auto printType
= [&](auto T
) {
349 OS
<< "typedef " << T
->getClangBuiltinStr() << " " << T
->getTypeStr()
353 constexpr int Log2LMULs
[] = {-3, -2, -1, 0, 1, 2, 3};
354 // Print RVV boolean types.
355 for (int Log2LMUL
: Log2LMULs
) {
356 auto T
= TypeCache
.computeType(BasicType::Int8
, Log2LMUL
,
357 PrototypeDescriptor::Mask
);
361 // Print RVV int/float types.
362 for (char I
: StringRef("csil")) {
363 BasicType BT
= ParseBasicType(I
);
364 for (int Log2LMUL
: Log2LMULs
) {
365 auto T
= TypeCache
.computeType(BT
, Log2LMUL
, PrototypeDescriptor::Vector
);
368 auto UT
= TypeCache
.computeType(
370 PrototypeDescriptor(BaseTypeModifier::Vector
,
371 VectorTypeModifier::NoModifier
,
372 TypeModifier::UnsignedInteger
));
375 for (int NF
= 2; NF
<= 8; ++NF
) {
376 auto TupleT
= TypeCache
.computeType(
378 PrototypeDescriptor(BaseTypeModifier::Vector
, getTupleVTM(NF
),
379 TypeModifier::SignedInteger
));
380 auto TupleUT
= TypeCache
.computeType(
382 PrototypeDescriptor(BaseTypeModifier::Vector
, getTupleVTM(NF
),
383 TypeModifier::UnsignedInteger
));
393 {BasicType::Float16
, BasicType::Float32
, BasicType::Float64
}) {
394 for (int Log2LMUL
: Log2LMULs
) {
395 auto T
= TypeCache
.computeType(BT
, Log2LMUL
, PrototypeDescriptor::Vector
);
398 for (int NF
= 2; NF
<= 8; ++NF
) {
399 auto TupleT
= TypeCache
.computeType(
401 PrototypeDescriptor(BaseTypeModifier::Vector
, getTupleVTM(NF
),
402 TypeModifier::Float
));
409 OS
<< "#define __riscv_v_intrinsic_overloading 1\n";
411 OS
<< "\n#ifdef __cplusplus\n";
413 OS
<< "#endif // __cplusplus\n";
414 OS
<< "#endif // __RISCV_VECTOR_H\n";
417 void RVVEmitter::createBuiltins(raw_ostream
&OS
) {
418 std::vector
<std::unique_ptr
<RVVIntrinsic
>> Defs
;
419 createRVVIntrinsics(Defs
);
421 // Map to keep track of which builtin names have already been emitted.
422 StringMap
<RVVIntrinsic
*> BuiltinMap
;
424 OS
<< "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n";
425 OS
<< "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, "
426 "ATTRS, \"zve32x\")\n";
428 for (auto &Def
: Defs
) {
430 BuiltinMap
.insert(std::make_pair(Def
->getBuiltinName(), Def
.get()));
432 // Verf that this would have produced the same builtin definition.
433 if (P
.first
->second
->hasBuiltinAlias() != Def
->hasBuiltinAlias())
434 PrintFatalError("Builtin with same name has different hasAutoDef");
435 else if (!Def
->hasBuiltinAlias() &&
436 P
.first
->second
->getBuiltinTypeStr() != Def
->getBuiltinTypeStr())
437 PrintFatalError("Builtin with same name has different type string");
440 OS
<< "RISCVV_BUILTIN(__builtin_rvv_" << Def
->getBuiltinName() << ",\"";
441 if (!Def
->hasBuiltinAlias())
442 OS
<< Def
->getBuiltinTypeStr();
443 OS
<< "\", \"n\")\n";
445 OS
<< "#undef RISCVV_BUILTIN\n";
448 void RVVEmitter::createCodeGen(raw_ostream
&OS
) {
449 std::vector
<std::unique_ptr
<RVVIntrinsic
>> Defs
;
450 createRVVIntrinsics(Defs
);
451 // IR name could be empty, use the stable sort preserves the relative order.
452 llvm::stable_sort(Defs
, [](const std::unique_ptr
<RVVIntrinsic
> &A
,
453 const std::unique_ptr
<RVVIntrinsic
> &B
) {
454 if (A
->getIRName() == B
->getIRName())
455 return (A
->getPolicyAttrs() < B
->getPolicyAttrs());
456 return (A
->getIRName() < B
->getIRName());
459 // Map to keep track of which builtin names have already been emitted.
460 StringMap
<RVVIntrinsic
*> BuiltinMap
;
462 // Print switch body when the ir name, ManualCodegen or policy changes from
463 // previous iteration.
464 RVVIntrinsic
*PrevDef
= Defs
.begin()->get();
465 for (auto &Def
: Defs
) {
466 StringRef CurIRName
= Def
->getIRName();
467 if (CurIRName
!= PrevDef
->getIRName() ||
468 (Def
->getManualCodegen() != PrevDef
->getManualCodegen()) ||
469 (Def
->getPolicyAttrs() != PrevDef
->getPolicyAttrs())) {
470 emitCodeGenSwitchBody(PrevDef
, OS
);
475 BuiltinMap
.insert(std::make_pair(Def
->getBuiltinName(), Def
.get()));
477 OS
<< "case RISCVVector::BI__builtin_rvv_" << Def
->getBuiltinName()
482 if (P
.first
->second
->getIRName() != Def
->getIRName())
483 PrintFatalError("Builtin with same name has different IRName");
484 else if (P
.first
->second
->getManualCodegen() != Def
->getManualCodegen())
485 PrintFatalError("Builtin with same name has different ManualCodegen");
486 else if (P
.first
->second
->isMasked() != Def
->isMasked())
487 PrintFatalError("Builtin with same name has different isMasked");
488 else if (P
.first
->second
->hasVL() != Def
->hasVL())
489 PrintFatalError("Builtin with same name has different hasVL");
490 else if (P
.first
->second
->getPolicyScheme() != Def
->getPolicyScheme())
491 PrintFatalError("Builtin with same name has different getPolicyScheme");
492 else if (P
.first
->second
->getIntrinsicTypes() != Def
->getIntrinsicTypes())
493 PrintFatalError("Builtin with same name has different IntrinsicTypes");
495 emitCodeGenSwitchBody(Defs
.back().get(), OS
);
499 void RVVEmitter::createRVVIntrinsics(
500 std::vector
<std::unique_ptr
<RVVIntrinsic
>> &Out
,
501 std::vector
<SemaRecord
> *SemaRecords
) {
502 std::vector
<Record
*> RV
= Records
.getAllDerivedDefinitions("RVVBuiltin");
504 StringRef Name
= R
->getValueAsString("Name");
505 StringRef SuffixProto
= R
->getValueAsString("Suffix");
506 StringRef OverloadedName
= R
->getValueAsString("OverloadedName");
507 StringRef OverloadedSuffixProto
= R
->getValueAsString("OverloadedSuffix");
508 StringRef Prototypes
= R
->getValueAsString("Prototype");
509 StringRef TypeRange
= R
->getValueAsString("TypeRange");
510 bool HasMasked
= R
->getValueAsBit("HasMasked");
511 bool HasMaskedOffOperand
= R
->getValueAsBit("HasMaskedOffOperand");
512 bool HasVL
= R
->getValueAsBit("HasVL");
513 Record
*MPSRecord
= R
->getValueAsDef("MaskedPolicyScheme");
514 auto MaskedPolicyScheme
=
515 static_cast<PolicyScheme
>(MPSRecord
->getValueAsInt("Value"));
516 Record
*UMPSRecord
= R
->getValueAsDef("UnMaskedPolicyScheme");
517 auto UnMaskedPolicyScheme
=
518 static_cast<PolicyScheme
>(UMPSRecord
->getValueAsInt("Value"));
519 std::vector
<int64_t> Log2LMULList
= R
->getValueAsListOfInts("Log2LMUL");
520 bool HasTailPolicy
= R
->getValueAsBit("HasTailPolicy");
521 bool HasMaskPolicy
= R
->getValueAsBit("HasMaskPolicy");
522 bool SupportOverloading
= R
->getValueAsBit("SupportOverloading");
523 bool HasBuiltinAlias
= R
->getValueAsBit("HasBuiltinAlias");
524 StringRef ManualCodegen
= R
->getValueAsString("ManualCodegen");
525 std::vector
<int64_t> IntrinsicTypes
=
526 R
->getValueAsListOfInts("IntrinsicTypes");
527 std::vector
<StringRef
> RequiredFeatures
=
528 R
->getValueAsListOfStrings("RequiredFeatures");
529 StringRef IRName
= R
->getValueAsString("IRName");
530 StringRef MaskedIRName
= R
->getValueAsString("MaskedIRName");
531 unsigned NF
= R
->getValueAsInt("NF");
532 bool IsTuple
= R
->getValueAsBit("IsTuple");
533 bool HasFRMRoundModeOp
= R
->getValueAsBit("HasFRMRoundModeOp");
535 const Policy DefaultPolicy
;
536 SmallVector
<Policy
> SupportedUnMaskedPolicies
=
537 RVVIntrinsic::getSupportedUnMaskedPolicies();
538 SmallVector
<Policy
> SupportedMaskedPolicies
=
539 RVVIntrinsic::getSupportedMaskedPolicies(HasTailPolicy
, HasMaskPolicy
);
541 // Parse prototype and create a list of primitive type with transformers
542 // (operand) in Prototype. Prototype[0] is output operand.
543 SmallVector
<PrototypeDescriptor
> BasicPrototype
=
544 parsePrototypes(Prototypes
);
546 SmallVector
<PrototypeDescriptor
> SuffixDesc
= parsePrototypes(SuffixProto
);
547 SmallVector
<PrototypeDescriptor
> OverloadedSuffixDesc
=
548 parsePrototypes(OverloadedSuffixProto
);
550 // Compute Builtin types
551 auto Prototype
= RVVIntrinsic::computeBuiltinTypes(
552 BasicPrototype
, /*IsMasked=*/false,
553 /*HasMaskedOffOperand=*/false, HasVL
, NF
, UnMaskedPolicyScheme
,
554 DefaultPolicy
, IsTuple
);
555 llvm::SmallVector
<PrototypeDescriptor
> MaskedPrototype
;
557 MaskedPrototype
= RVVIntrinsic::computeBuiltinTypes(
558 BasicPrototype
, /*IsMasked=*/true, HasMaskedOffOperand
, HasVL
, NF
,
559 MaskedPolicyScheme
, DefaultPolicy
, IsTuple
);
561 // Create Intrinsics for each type and LMUL.
562 for (char I
: TypeRange
) {
563 for (int Log2LMUL
: Log2LMULList
) {
564 BasicType BT
= ParseBasicType(I
);
565 std::optional
<RVVTypes
> Types
=
566 TypeCache
.computeTypes(BT
, Log2LMUL
, NF
, Prototype
);
567 // Ignored to create new intrinsic if there are any illegal types.
572 RVVIntrinsic::getSuffixStr(TypeCache
, BT
, Log2LMUL
, SuffixDesc
);
573 auto OverloadedSuffixStr
= RVVIntrinsic::getSuffixStr(
574 TypeCache
, BT
, Log2LMUL
, OverloadedSuffixDesc
);
575 // Create a unmasked intrinsic
576 Out
.push_back(std::make_unique
<RVVIntrinsic
>(
577 Name
, SuffixStr
, OverloadedName
, OverloadedSuffixStr
, IRName
,
578 /*IsMasked=*/false, /*HasMaskedOffOperand=*/false, HasVL
,
579 UnMaskedPolicyScheme
, SupportOverloading
, HasBuiltinAlias
,
580 ManualCodegen
, *Types
, IntrinsicTypes
, RequiredFeatures
, NF
,
581 DefaultPolicy
, HasFRMRoundModeOp
));
582 if (UnMaskedPolicyScheme
!= PolicyScheme::SchemeNone
)
583 for (auto P
: SupportedUnMaskedPolicies
) {
584 SmallVector
<PrototypeDescriptor
> PolicyPrototype
=
585 RVVIntrinsic::computeBuiltinTypes(
586 BasicPrototype
, /*IsMasked=*/false,
587 /*HasMaskedOffOperand=*/false, HasVL
, NF
,
588 UnMaskedPolicyScheme
, P
, IsTuple
);
589 std::optional
<RVVTypes
> PolicyTypes
=
590 TypeCache
.computeTypes(BT
, Log2LMUL
, NF
, PolicyPrototype
);
591 Out
.push_back(std::make_unique
<RVVIntrinsic
>(
592 Name
, SuffixStr
, OverloadedName
, OverloadedSuffixStr
, IRName
,
593 /*IsMask=*/false, /*HasMaskedOffOperand=*/false, HasVL
,
594 UnMaskedPolicyScheme
, SupportOverloading
, HasBuiltinAlias
,
595 ManualCodegen
, *PolicyTypes
, IntrinsicTypes
, RequiredFeatures
,
596 NF
, P
, HasFRMRoundModeOp
));
600 // Create a masked intrinsic
601 std::optional
<RVVTypes
> MaskTypes
=
602 TypeCache
.computeTypes(BT
, Log2LMUL
, NF
, MaskedPrototype
);
603 Out
.push_back(std::make_unique
<RVVIntrinsic
>(
604 Name
, SuffixStr
, OverloadedName
, OverloadedSuffixStr
, MaskedIRName
,
605 /*IsMasked=*/true, HasMaskedOffOperand
, HasVL
, MaskedPolicyScheme
,
606 SupportOverloading
, HasBuiltinAlias
, ManualCodegen
, *MaskTypes
,
607 IntrinsicTypes
, RequiredFeatures
, NF
, DefaultPolicy
,
609 if (MaskedPolicyScheme
== PolicyScheme::SchemeNone
)
611 for (auto P
: SupportedMaskedPolicies
) {
612 SmallVector
<PrototypeDescriptor
> PolicyPrototype
=
613 RVVIntrinsic::computeBuiltinTypes(
614 BasicPrototype
, /*IsMasked=*/true, HasMaskedOffOperand
, HasVL
,
615 NF
, MaskedPolicyScheme
, P
, IsTuple
);
616 std::optional
<RVVTypes
> PolicyTypes
=
617 TypeCache
.computeTypes(BT
, Log2LMUL
, NF
, PolicyPrototype
);
618 Out
.push_back(std::make_unique
<RVVIntrinsic
>(
619 Name
, SuffixStr
, OverloadedName
, OverloadedSuffixStr
,
620 MaskedIRName
, /*IsMasked=*/true, HasMaskedOffOperand
, HasVL
,
621 MaskedPolicyScheme
, SupportOverloading
, HasBuiltinAlias
,
622 ManualCodegen
, *PolicyTypes
, IntrinsicTypes
, RequiredFeatures
, NF
,
623 P
, HasFRMRoundModeOp
));
625 } // End for Log2LMULList
626 } // End for TypeRange
628 // We don't emit vsetvli and vsetvlimax for SemaRecord.
629 // They are written in riscv_vector.td and will emit those marco define in
631 if (Name
== "vsetvli" || Name
== "vsetvlimax")
639 SR
.Name
= Name
.str();
640 SR
.OverloadedName
= OverloadedName
.str();
641 BasicType TypeRangeMask
= BasicType::Unknown
;
642 for (char I
: TypeRange
)
643 TypeRangeMask
|= ParseBasicType(I
);
645 SR
.TypeRangeMask
= static_cast<unsigned>(TypeRangeMask
);
647 unsigned Log2LMULMask
= 0;
648 for (int Log2LMUL
: Log2LMULList
)
649 Log2LMULMask
|= 1 << (Log2LMUL
+ 3);
651 SR
.Log2LMULMask
= Log2LMULMask
;
653 SR
.RequiredExtensions
= 0;
654 for (auto RequiredFeature
: RequiredFeatures
) {
655 RVVRequire RequireExt
= StringSwitch
<RVVRequire
>(RequiredFeature
)
656 .Case("RV64", RVV_REQ_RV64
)
657 .Case("ZvfhminOrZvfh", RVV_REQ_ZvfhminOrZvfh
)
658 .Case("Xsfvcp", RVV_REQ_Xsfvcp
)
659 .Case("Xsfvqmaccdod", RVV_REQ_Xsfvqmaccdod
)
660 .Case("Xsfvqmaccqoq", RVV_REQ_Xsfvqmaccqoq
)
661 .Case("Zvbb", RVV_REQ_Zvbb
)
662 .Case("Zvbc", RVV_REQ_Zvbc
)
663 .Case("Zvkb", RVV_REQ_Zvkb
)
664 .Case("Zvkg", RVV_REQ_Zvkg
)
665 .Case("Zvkned", RVV_REQ_Zvkned
)
666 .Case("Zvknha", RVV_REQ_Zvknha
)
667 .Case("Zvksed", RVV_REQ_Zvksed
)
668 .Case("Zvksh", RVV_REQ_Zvksh
)
669 .Default(RVV_REQ_None
);
670 assert(RequireExt
!= RVV_REQ_None
&& "Unrecognized required feature?");
671 SR
.RequiredExtensions
|= RequireExt
;
675 SR
.HasMasked
= HasMasked
;
677 SR
.HasMaskedOffOperand
= HasMaskedOffOperand
;
678 SR
.HasTailPolicy
= HasTailPolicy
;
679 SR
.HasMaskPolicy
= HasMaskPolicy
;
680 SR
.UnMaskedPolicyScheme
= static_cast<uint8_t>(UnMaskedPolicyScheme
);
681 SR
.MaskedPolicyScheme
= static_cast<uint8_t>(MaskedPolicyScheme
);
682 SR
.Prototype
= std::move(BasicPrototype
);
683 SR
.Suffix
= parsePrototypes(SuffixProto
);
684 SR
.OverloadedSuffix
= parsePrototypes(OverloadedSuffixProto
);
685 SR
.IsTuple
= IsTuple
;
686 SR
.HasFRMRoundModeOp
= HasFRMRoundModeOp
;
688 SemaRecords
->push_back(SR
);
692 void RVVEmitter::printHeaderCode(raw_ostream
&OS
) {
693 std::vector
<Record
*> RVVHeaders
=
694 Records
.getAllDerivedDefinitions("RVVHeader");
695 for (auto *R
: RVVHeaders
) {
696 StringRef HeaderCodeStr
= R
->getValueAsString("HeaderCode");
697 OS
<< HeaderCodeStr
.str();
701 void RVVEmitter::createRVVIntrinsicRecords(std::vector
<RVVIntrinsicRecord
> &Out
,
702 SemaSignatureTable
&SST
,
703 ArrayRef
<SemaRecord
> SemaRecords
) {
704 SST
.init(SemaRecords
);
706 for (const auto &SR
: SemaRecords
) {
707 Out
.emplace_back(RVVIntrinsicRecord());
708 RVVIntrinsicRecord
&R
= Out
.back();
709 R
.Name
= SR
.Name
.c_str();
710 R
.OverloadedName
= SR
.OverloadedName
.c_str();
711 R
.PrototypeIndex
= SST
.getIndex(SR
.Prototype
);
712 R
.SuffixIndex
= SST
.getIndex(SR
.Suffix
);
713 R
.OverloadedSuffixIndex
= SST
.getIndex(SR
.OverloadedSuffix
);
714 R
.PrototypeLength
= SR
.Prototype
.size();
715 R
.SuffixLength
= SR
.Suffix
.size();
716 R
.OverloadedSuffixSize
= SR
.OverloadedSuffix
.size();
717 R
.RequiredExtensions
= SR
.RequiredExtensions
;
718 R
.TypeRangeMask
= SR
.TypeRangeMask
;
719 R
.Log2LMULMask
= SR
.Log2LMULMask
;
721 R
.HasMasked
= SR
.HasMasked
;
723 R
.HasMaskedOffOperand
= SR
.HasMaskedOffOperand
;
724 R
.HasTailPolicy
= SR
.HasTailPolicy
;
725 R
.HasMaskPolicy
= SR
.HasMaskPolicy
;
726 R
.UnMaskedPolicyScheme
= SR
.UnMaskedPolicyScheme
;
727 R
.MaskedPolicyScheme
= SR
.MaskedPolicyScheme
;
728 R
.IsTuple
= SR
.IsTuple
;
729 R
.HasFRMRoundModeOp
= SR
.HasFRMRoundModeOp
;
731 assert(R
.PrototypeIndex
!=
732 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX
));
733 assert(R
.SuffixIndex
!=
734 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX
));
735 assert(R
.OverloadedSuffixIndex
!=
736 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX
));
740 void RVVEmitter::createSema(raw_ostream
&OS
) {
741 std::vector
<std::unique_ptr
<RVVIntrinsic
>> Defs
;
742 std::vector
<RVVIntrinsicRecord
> RVVIntrinsicRecords
;
743 SemaSignatureTable SST
;
744 std::vector
<SemaRecord
> SemaRecords
;
746 createRVVIntrinsics(Defs
, &SemaRecords
);
748 createRVVIntrinsicRecords(RVVIntrinsicRecords
, SST
, SemaRecords
);
750 // Emit signature table for SemaRISCVVectorLookup.cpp.
751 OS
<< "#ifdef DECL_SIGNATURE_TABLE\n";
755 // Emit RVVIntrinsicRecords for SemaRISCVVectorLookup.cpp.
756 OS
<< "#ifdef DECL_INTRINSIC_RECORDS\n";
757 for (const RVVIntrinsicRecord
&Record
: RVVIntrinsicRecords
)
763 void EmitRVVHeader(RecordKeeper
&Records
, raw_ostream
&OS
) {
764 RVVEmitter(Records
).createHeader(OS
);
767 void EmitRVVBuiltins(RecordKeeper
&Records
, raw_ostream
&OS
) {
768 RVVEmitter(Records
).createBuiltins(OS
);
771 void EmitRVVBuiltinCG(RecordKeeper
&Records
, raw_ostream
&OS
) {
772 RVVEmitter(Records
).createCodeGen(OS
);
775 void EmitRVVBuiltinSema(RecordKeeper
&Records
, raw_ostream
&OS
) {
776 RVVEmitter(Records
).createSema(OS
);
779 } // End namespace clang