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/StringExtras.h"
20 #include "llvm/ADT/StringMap.h"
21 #include "llvm/ADT/StringSwitch.h"
22 #include "llvm/ADT/Twine.h"
23 #include "llvm/TableGen/Error.h"
24 #include "llvm/TableGen/Record.h"
28 using namespace clang::RISCV
;
32 // Intrinsic name, e.g. vadd_vv
35 // Overloaded intrinsic name, could be empty if can be computed from Name
37 std::string OverloadedName
;
39 // Supported type, mask of BasicType.
40 unsigned TypeRangeMask
;
43 unsigned Log2LMULMask
;
45 // Required extensions for this intrinsic.
46 uint32_t RequiredExtensions
;
48 // Prototype for this intrinsic.
49 SmallVector
<PrototypeDescriptor
> Prototype
;
51 // Suffix of intrinsic name.
52 SmallVector
<PrototypeDescriptor
> Suffix
;
54 // Suffix of overloaded intrinsic name.
55 SmallVector
<PrototypeDescriptor
> OverloadedSuffix
;
57 // Number of field, large than 1 if it's segment load/store.
62 bool HasMaskedOffOperand
:1;
63 bool HasTailPolicy
: 1;
64 bool HasMaskPolicy
: 1;
65 bool HasFRMRoundModeOp
: 1;
67 LLVM_PREFERRED_TYPE(PolicyScheme
)
68 uint8_t UnMaskedPolicyScheme
: 2;
69 LLVM_PREFERRED_TYPE(PolicyScheme
)
70 uint8_t MaskedPolicyScheme
: 2;
73 // Compressed function signature table.
74 class SemaSignatureTable
{
76 std::vector
<PrototypeDescriptor
> SignatureTable
;
78 void insert(ArrayRef
<PrototypeDescriptor
> Signature
);
81 static constexpr unsigned INVALID_INDEX
= ~0U;
83 // Create compressed signature table from SemaRecords.
84 void init(ArrayRef
<SemaRecord
> SemaRecords
);
86 // Query the Signature, return INVALID_INDEX if not found.
87 unsigned getIndex(ArrayRef
<PrototypeDescriptor
> Signature
);
89 /// Print signature table in RVVHeader Record to \p OS
90 void print(raw_ostream
&OS
);
95 const RecordKeeper
&Records
;
96 RVVTypeCache TypeCache
;
99 RVVEmitter(const RecordKeeper
&R
) : Records(R
) {}
101 /// Emit riscv_vector.h
102 void createHeader(raw_ostream
&o
);
104 /// Emit all the __builtin prototypes and code needed by Sema.
105 void createBuiltins(raw_ostream
&o
);
107 /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
108 void createCodeGen(raw_ostream
&o
);
110 /// Emit all the information needed by SemaRISCVVectorLookup.cpp.
111 /// We've large number of intrinsic function for RVV, creating a customized
112 /// could speed up the compilation time.
113 void createSema(raw_ostream
&o
);
116 /// Create all intrinsics and add them to \p Out and SemaRecords.
117 void createRVVIntrinsics(std::vector
<std::unique_ptr
<RVVIntrinsic
>> &Out
,
118 std::vector
<SemaRecord
> *SemaRecords
= nullptr);
119 /// Create all intrinsic records and SemaSignatureTable from SemaRecords.
120 void createRVVIntrinsicRecords(std::vector
<RVVIntrinsicRecord
> &Out
,
121 SemaSignatureTable
&SST
,
122 ArrayRef
<SemaRecord
> SemaRecords
);
124 /// Print HeaderCode in RVVHeader Record to \p Out
125 void printHeaderCode(raw_ostream
&OS
);
130 static BasicType
ParseBasicType(char c
) {
133 return BasicType::Int8
;
136 return BasicType::Int16
;
139 return BasicType::Int32
;
142 return BasicType::Int64
;
145 return BasicType::Float16
;
148 return BasicType::Float32
;
151 return BasicType::Float64
;
154 return BasicType::BFloat16
;
157 return BasicType::Unknown
;
161 static VectorTypeModifier
getTupleVTM(unsigned NF
) {
162 assert(2 <= NF
&& NF
<= 8 && "2 <= NF <= 8");
163 return static_cast<VectorTypeModifier
>(
164 static_cast<uint8_t>(VectorTypeModifier::Tuple2
) + (NF
- 2));
167 static unsigned getIndexedLoadStorePtrIdx(const RVVIntrinsic
*RVVI
) {
168 // We need a special rule for segment load/store since the data width is not
169 // encoded in the intrinsic name itself.
170 const StringRef IRName
= RVVI
->getIRName();
171 constexpr unsigned RVV_VTA
= 0x1;
172 constexpr unsigned RVV_VMA
= 0x2;
174 if (IRName
.starts_with("vloxseg") || IRName
.starts_with("vluxseg")) {
176 (RVVI
->isMasked() && (RVVI
->getPolicyAttrsBits() & RVV_VTA
) &&
177 (RVVI
->getPolicyAttrsBits() & RVV_VMA
)) ||
178 (!RVVI
->isMasked() && (RVVI
->getPolicyAttrsBits() & RVV_VTA
));
179 return RVVI
->isMasked() ? NoPassthru
? 1 : 2 : NoPassthru
? 0 : 1;
181 if (IRName
.starts_with("vsoxseg") || IRName
.starts_with("vsuxseg"))
182 return RVVI
->isMasked() ? 1 : 0;
187 // This function is used to get the log2SEW of each segment load/store, this
188 // prevent to add a member to RVVIntrinsic.
189 static unsigned getSegInstLog2SEW(StringRef InstName
) {
191 // We need a special rule for indexed segment load/store since the data width
192 // is not encoded in the intrinsic name itself.
193 if (InstName
.starts_with("vloxseg") || InstName
.starts_with("vluxseg") ||
194 InstName
.starts_with("vsoxseg") || InstName
.starts_with("vsuxseg"))
197 #define KEY_VAL(KEY, VAL) {#KEY, VAL}
198 #define KEY_VAL_ALL_W_POLICY(KEY, VAL) \
200 KEY_VAL(KEY ## _tu, VAL), \
201 KEY_VAL(KEY ## _tum, VAL), \
202 KEY_VAL(KEY ## _tumu, VAL), \
203 KEY_VAL(KEY ## _mu, VAL)
205 #define KEY_VAL_ALL_NF_BASE(MACRO_NAME, NAME, SEW, LOG2SEW, FF) \
206 MACRO_NAME(NAME ## 2e ## SEW ## FF, LOG2SEW), \
207 MACRO_NAME(NAME ## 3e ## SEW ## FF, LOG2SEW), \
208 MACRO_NAME(NAME ## 4e ## SEW ## FF, LOG2SEW), \
209 MACRO_NAME(NAME ## 5e ## SEW ## FF, LOG2SEW), \
210 MACRO_NAME(NAME ## 6e ## SEW ## FF, LOG2SEW), \
211 MACRO_NAME(NAME ## 7e ## SEW ## FF, LOG2SEW), \
212 MACRO_NAME(NAME ## 8e ## SEW ## FF, LOG2SEW)
214 #define KEY_VAL_ALL_NF(NAME, SEW, LOG2SEW) \
215 KEY_VAL_ALL_NF_BASE(KEY_VAL_ALL_W_POLICY, NAME, SEW, LOG2SEW,)
217 #define KEY_VAL_FF_ALL_NF(NAME, SEW, LOG2SEW) \
218 KEY_VAL_ALL_NF_BASE(KEY_VAL_ALL_W_POLICY, NAME, SEW, LOG2SEW, ff)
220 #define KEY_VAL_ALL_NF_SEW_BASE(MACRO_NAME, NAME) \
221 MACRO_NAME(NAME, 8, 3), \
222 MACRO_NAME(NAME, 16, 4), \
223 MACRO_NAME(NAME, 32, 5), \
224 MACRO_NAME(NAME, 64, 6)
226 #define KEY_VAL_ALL_NF_SEW(NAME) \
227 KEY_VAL_ALL_NF_SEW_BASE(KEY_VAL_ALL_NF, NAME)
229 #define KEY_VAL_FF_ALL_NF_SEW(NAME) \
230 KEY_VAL_ALL_NF_SEW_BASE(KEY_VAL_FF_ALL_NF, NAME)
233 static StringMap
<unsigned> SegInsts
= {
234 KEY_VAL_ALL_NF_SEW(vlseg
), KEY_VAL_FF_ALL_NF_SEW(vlseg
),
235 KEY_VAL_ALL_NF_SEW(vlsseg
), KEY_VAL_ALL_NF_SEW(vsseg
),
236 KEY_VAL_ALL_NF_SEW(vssseg
)};
238 #undef KEY_VAL_ALL_NF_SEW
239 #undef KEY_VAL_ALL_NF
242 return SegInsts
.lookup(InstName
);
245 void emitCodeGenSwitchBody(const RVVIntrinsic
*RVVI
, raw_ostream
&OS
) {
246 if (!RVVI
->getIRName().empty())
247 OS
<< " ID = Intrinsic::riscv_" + RVVI
->getIRName() + ";\n";
249 OS
<< " PolicyAttrs = " << RVVI
->getPolicyAttrsBits() << ";\n";
250 OS
<< " SegInstSEW = " << getSegInstLog2SEW(RVVI
->getOverloadedName())
253 if (RVVI
->hasManualCodegen()) {
254 OS
<< "IsMasked = " << (RVVI
->isMasked() ? "true" : "false") << ";\n";
256 // Skip the non-indexed load/store and compatible header load/store.
257 OS
<< "if (SegInstSEW == (unsigned)-1) {\n";
258 OS
<< " auto PointeeType = E->getArg(" << getIndexedLoadStorePtrIdx(RVVI
)
259 << " )->getType()->getPointeeType();\n";
260 OS
<< " SegInstSEW = "
261 " llvm::Log2_64(getContext().getTypeSize(PointeeType));\n}\n";
263 OS
<< RVVI
->getManualCodegen();
268 for (const auto &I
: enumerate(RVVI
->getInputTypes())) {
269 if (I
.value()->isPointer()) {
270 assert(RVVI
->getIntrinsicTypes().front() == -1 &&
271 "RVVI should be vector load intrinsic.");
275 if (RVVI
->isMasked()) {
277 OS
<< " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n";
278 if (RVVI
->hasPolicyOperand())
279 OS
<< " Ops.push_back(ConstantInt::get(Ops.back()->getType(),"
281 if (RVVI
->hasMaskedOffOperand() && RVVI
->getPolicyAttrs().isTAMAPolicy())
282 OS
<< " Ops.insert(Ops.begin(), "
283 "llvm::PoisonValue::get(ResultType));\n";
284 // Masked reduction cases.
285 if (!RVVI
->hasMaskedOffOperand() && RVVI
->hasPassthruOperand() &&
286 RVVI
->getPolicyAttrs().isTAMAPolicy())
287 OS
<< " Ops.insert(Ops.begin(), "
288 "llvm::PoisonValue::get(ResultType));\n";
290 OS
<< " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n";
293 if (RVVI
->hasPolicyOperand())
294 OS
<< " Ops.push_back(ConstantInt::get(Ops.back()->getType(), "
296 else if (RVVI
->hasPassthruOperand() && RVVI
->getPolicyAttrs().isTAPolicy())
297 OS
<< " Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));\n";
300 OS
<< " IntrinsicTypes = {";
302 for (const auto &Idx
: RVVI
->getIntrinsicTypes()) {
304 OS
<< LS
<< "ResultType";
306 OS
<< LS
<< "Ops[" << Idx
<< "]->getType()";
309 // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is
310 // always last operand.
312 OS
<< ", Ops.back()->getType()";
317 //===----------------------------------------------------------------------===//
318 // SemaSignatureTable implementation
319 //===----------------------------------------------------------------------===//
320 void SemaSignatureTable::init(ArrayRef
<SemaRecord
> SemaRecords
) {
321 // Sort signature entries by length, let longer signature insert first, to
322 // make it more possible to reuse table entries, that can reduce ~10% table
325 bool operator()(const SmallVector
<PrototypeDescriptor
> &A
,
326 const SmallVector
<PrototypeDescriptor
> &B
) const {
327 if (A
.size() != B
.size())
328 return A
.size() > B
.size();
330 size_t Len
= A
.size();
331 for (size_t i
= 0; i
< Len
; ++i
) {
340 std::set
<SmallVector
<PrototypeDescriptor
>, Compare
> Signatures
;
341 auto InsertToSignatureSet
=
342 [&](const SmallVector
<PrototypeDescriptor
> &Signature
) {
343 if (Signature
.empty())
346 Signatures
.insert(Signature
);
349 assert(!SemaRecords
.empty());
351 for (const SemaRecord
&SR
: SemaRecords
) {
352 InsertToSignatureSet(SR
.Prototype
);
353 InsertToSignatureSet(SR
.Suffix
);
354 InsertToSignatureSet(SR
.OverloadedSuffix
);
357 for (auto &Sig
: Signatures
)
361 void SemaSignatureTable::insert(ArrayRef
<PrototypeDescriptor
> Signature
) {
362 if (getIndex(Signature
) != INVALID_INDEX
)
365 // Insert Signature into SignatureTable if not found in the table.
366 SignatureTable
.insert(SignatureTable
.begin(), Signature
.begin(),
370 unsigned SemaSignatureTable::getIndex(ArrayRef
<PrototypeDescriptor
> Signature
) {
371 // Empty signature could be point into any index since there is length
372 // field when we use, so just always point it to 0.
373 if (Signature
.empty())
376 // Checking Signature already in table or not.
377 if (Signature
.size() <= SignatureTable
.size()) {
378 size_t Bound
= SignatureTable
.size() - Signature
.size() + 1;
379 for (size_t Index
= 0; Index
< Bound
; ++Index
) {
380 if (equal(Signature
.begin(), Signature
.end(),
381 SignatureTable
.begin() + Index
))
386 return INVALID_INDEX
;
389 void SemaSignatureTable::print(raw_ostream
&OS
) {
390 for (const auto &Sig
: SignatureTable
)
391 OS
<< "PrototypeDescriptor(" << static_cast<int>(Sig
.PT
) << ", "
392 << static_cast<int>(Sig
.VTM
) << ", " << static_cast<int>(Sig
.TM
)
396 //===----------------------------------------------------------------------===//
397 // RVVEmitter implementation
398 //===----------------------------------------------------------------------===//
399 void RVVEmitter::createHeader(raw_ostream
&OS
) {
401 OS
<< "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics "
402 "-------------------===\n"
405 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
407 " * See https://llvm.org/LICENSE.txt for license information.\n"
408 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
410 " *===-----------------------------------------------------------------"
414 OS
<< "#ifndef __RISCV_VECTOR_H\n";
415 OS
<< "#define __RISCV_VECTOR_H\n\n";
417 OS
<< "#include <stdint.h>\n";
418 OS
<< "#include <stddef.h>\n\n";
420 OS
<< "#ifdef __cplusplus\n";
421 OS
<< "extern \"C\" {\n";
424 OS
<< "#pragma clang riscv intrinsic vector\n\n";
428 auto printType
= [&](auto T
) {
429 OS
<< "typedef " << T
->getClangBuiltinStr() << " " << T
->getTypeStr()
433 constexpr int Log2LMULs
[] = {-3, -2, -1, 0, 1, 2, 3};
434 // Print RVV boolean types.
435 for (int Log2LMUL
: Log2LMULs
) {
436 auto T
= TypeCache
.computeType(BasicType::Int8
, Log2LMUL
,
437 PrototypeDescriptor::Mask
);
441 // Print RVV int/float types.
442 for (char I
: StringRef("csil")) {
443 BasicType BT
= ParseBasicType(I
);
444 for (int Log2LMUL
: Log2LMULs
) {
445 auto T
= TypeCache
.computeType(BT
, Log2LMUL
, PrototypeDescriptor::Vector
);
448 auto UT
= TypeCache
.computeType(
450 PrototypeDescriptor(BaseTypeModifier::Vector
,
451 VectorTypeModifier::NoModifier
,
452 TypeModifier::UnsignedInteger
));
455 for (int NF
= 2; NF
<= 8; ++NF
) {
456 auto TupleT
= TypeCache
.computeType(
458 PrototypeDescriptor(BaseTypeModifier::Vector
, getTupleVTM(NF
),
459 TypeModifier::SignedInteger
));
460 auto TupleUT
= TypeCache
.computeType(
462 PrototypeDescriptor(BaseTypeModifier::Vector
, getTupleVTM(NF
),
463 TypeModifier::UnsignedInteger
));
472 for (BasicType BT
: {BasicType::Float16
, BasicType::Float32
,
473 BasicType::Float64
, BasicType::BFloat16
}) {
474 for (int Log2LMUL
: Log2LMULs
) {
475 auto T
= TypeCache
.computeType(BT
, Log2LMUL
, PrototypeDescriptor::Vector
);
478 for (int NF
= 2; NF
<= 8; ++NF
) {
479 auto TupleT
= TypeCache
.computeType(
481 PrototypeDescriptor(BaseTypeModifier::Vector
, getTupleVTM(NF
),
482 (BT
== BasicType::BFloat16
483 ? TypeModifier::BFloat
484 : TypeModifier::Float
)));
491 OS
<< "#define __riscv_v_intrinsic_overloading 1\n";
493 OS
<< "\n#ifdef __cplusplus\n";
495 OS
<< "#endif // __cplusplus\n";
496 OS
<< "#endif // __RISCV_VECTOR_H\n";
499 void RVVEmitter::createBuiltins(raw_ostream
&OS
) {
500 std::vector
<std::unique_ptr
<RVVIntrinsic
>> Defs
;
501 createRVVIntrinsics(Defs
);
503 // Map to keep track of which builtin names have already been emitted.
504 StringMap
<RVVIntrinsic
*> BuiltinMap
;
506 OS
<< "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n";
507 OS
<< "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, "
508 "ATTRS, \"zve32x\")\n";
510 for (auto &Def
: Defs
) {
512 BuiltinMap
.insert(std::make_pair(Def
->getBuiltinName(), Def
.get()));
514 // Verf that this would have produced the same builtin definition.
515 if (P
.first
->second
->hasBuiltinAlias() != Def
->hasBuiltinAlias())
516 PrintFatalError("Builtin with same name has different hasAutoDef");
517 else if (!Def
->hasBuiltinAlias() &&
518 P
.first
->second
->getBuiltinTypeStr() != Def
->getBuiltinTypeStr())
519 PrintFatalError("Builtin with same name has different type string");
522 OS
<< "RISCVV_BUILTIN(__builtin_rvv_" << Def
->getBuiltinName() << ",\"";
523 if (!Def
->hasBuiltinAlias())
524 OS
<< Def
->getBuiltinTypeStr();
525 OS
<< "\", \"n\")\n";
527 OS
<< "#undef RISCVV_BUILTIN\n";
530 void RVVEmitter::createCodeGen(raw_ostream
&OS
) {
531 std::vector
<std::unique_ptr
<RVVIntrinsic
>> Defs
;
532 createRVVIntrinsics(Defs
);
533 // IR name could be empty, use the stable sort preserves the relative order.
534 stable_sort(Defs
, [](const std::unique_ptr
<RVVIntrinsic
> &A
,
535 const std::unique_ptr
<RVVIntrinsic
> &B
) {
536 if (A
->getIRName() == B
->getIRName())
537 return (A
->getPolicyAttrs() < B
->getPolicyAttrs());
538 return (A
->getIRName() < B
->getIRName());
541 // Map to keep track of which builtin names have already been emitted.
542 StringMap
<RVVIntrinsic
*> BuiltinMap
;
544 // Print switch body when the ir name, ManualCodegen, policy or log2sew
545 // changes from previous iteration.
546 RVVIntrinsic
*PrevDef
= Defs
.begin()->get();
547 for (auto &Def
: Defs
) {
548 StringRef CurIRName
= Def
->getIRName();
549 if (CurIRName
!= PrevDef
->getIRName() ||
550 (Def
->getManualCodegen() != PrevDef
->getManualCodegen()) ||
551 (Def
->getPolicyAttrs() != PrevDef
->getPolicyAttrs()) ||
552 (getSegInstLog2SEW(Def
->getOverloadedName()) !=
553 getSegInstLog2SEW(PrevDef
->getOverloadedName()))) {
554 emitCodeGenSwitchBody(PrevDef
, OS
);
559 BuiltinMap
.insert(std::make_pair(Def
->getBuiltinName(), Def
.get()));
561 OS
<< "case RISCVVector::BI__builtin_rvv_" << Def
->getBuiltinName()
566 if (P
.first
->second
->getIRName() != Def
->getIRName())
567 PrintFatalError("Builtin with same name has different IRName");
568 else if (P
.first
->second
->getManualCodegen() != Def
->getManualCodegen())
569 PrintFatalError("Builtin with same name has different ManualCodegen");
570 else if (P
.first
->second
->isMasked() != Def
->isMasked())
571 PrintFatalError("Builtin with same name has different isMasked");
572 else if (P
.first
->second
->hasVL() != Def
->hasVL())
573 PrintFatalError("Builtin with same name has different hasVL");
574 else if (P
.first
->second
->getPolicyScheme() != Def
->getPolicyScheme())
575 PrintFatalError("Builtin with same name has different getPolicyScheme");
576 else if (P
.first
->second
->getIntrinsicTypes() != Def
->getIntrinsicTypes())
577 PrintFatalError("Builtin with same name has different IntrinsicTypes");
579 emitCodeGenSwitchBody(Defs
.back().get(), OS
);
583 void RVVEmitter::createRVVIntrinsics(
584 std::vector
<std::unique_ptr
<RVVIntrinsic
>> &Out
,
585 std::vector
<SemaRecord
> *SemaRecords
) {
586 for (const Record
*R
: Records
.getAllDerivedDefinitions("RVVBuiltin")) {
587 StringRef Name
= R
->getValueAsString("Name");
588 StringRef SuffixProto
= R
->getValueAsString("Suffix");
589 StringRef OverloadedName
= R
->getValueAsString("OverloadedName");
590 StringRef OverloadedSuffixProto
= R
->getValueAsString("OverloadedSuffix");
591 StringRef Prototypes
= R
->getValueAsString("Prototype");
592 StringRef TypeRange
= R
->getValueAsString("TypeRange");
593 bool HasMasked
= R
->getValueAsBit("HasMasked");
594 bool HasMaskedOffOperand
= R
->getValueAsBit("HasMaskedOffOperand");
595 bool HasVL
= R
->getValueAsBit("HasVL");
596 const Record
*MPSRecord
= R
->getValueAsDef("MaskedPolicyScheme");
597 auto MaskedPolicyScheme
=
598 static_cast<PolicyScheme
>(MPSRecord
->getValueAsInt("Value"));
599 const Record
*UMPSRecord
= R
->getValueAsDef("UnMaskedPolicyScheme");
600 auto UnMaskedPolicyScheme
=
601 static_cast<PolicyScheme
>(UMPSRecord
->getValueAsInt("Value"));
602 std::vector
<int64_t> Log2LMULList
= R
->getValueAsListOfInts("Log2LMUL");
603 bool HasTailPolicy
= R
->getValueAsBit("HasTailPolicy");
604 bool HasMaskPolicy
= R
->getValueAsBit("HasMaskPolicy");
605 bool SupportOverloading
= R
->getValueAsBit("SupportOverloading");
606 bool HasBuiltinAlias
= R
->getValueAsBit("HasBuiltinAlias");
607 StringRef ManualCodegen
= R
->getValueAsString("ManualCodegen");
608 std::vector
<int64_t> IntrinsicTypes
=
609 R
->getValueAsListOfInts("IntrinsicTypes");
610 std::vector
<StringRef
> RequiredFeatures
=
611 R
->getValueAsListOfStrings("RequiredFeatures");
612 StringRef IRName
= R
->getValueAsString("IRName");
613 StringRef MaskedIRName
= R
->getValueAsString("MaskedIRName");
614 unsigned NF
= R
->getValueAsInt("NF");
615 bool IsTuple
= R
->getValueAsBit("IsTuple");
616 bool HasFRMRoundModeOp
= R
->getValueAsBit("HasFRMRoundModeOp");
618 const Policy DefaultPolicy
;
619 SmallVector
<Policy
> SupportedUnMaskedPolicies
=
620 RVVIntrinsic::getSupportedUnMaskedPolicies();
621 SmallVector
<Policy
> SupportedMaskedPolicies
=
622 RVVIntrinsic::getSupportedMaskedPolicies(HasTailPolicy
, HasMaskPolicy
);
624 // Parse prototype and create a list of primitive type with transformers
625 // (operand) in Prototype. Prototype[0] is output operand.
626 SmallVector
<PrototypeDescriptor
> BasicPrototype
=
627 parsePrototypes(Prototypes
);
629 SmallVector
<PrototypeDescriptor
> SuffixDesc
= parsePrototypes(SuffixProto
);
630 SmallVector
<PrototypeDescriptor
> OverloadedSuffixDesc
=
631 parsePrototypes(OverloadedSuffixProto
);
633 // Compute Builtin types
634 auto Prototype
= RVVIntrinsic::computeBuiltinTypes(
635 BasicPrototype
, /*IsMasked=*/false,
636 /*HasMaskedOffOperand=*/false, HasVL
, NF
, UnMaskedPolicyScheme
,
637 DefaultPolicy
, IsTuple
);
638 SmallVector
<PrototypeDescriptor
> MaskedPrototype
;
640 MaskedPrototype
= RVVIntrinsic::computeBuiltinTypes(
641 BasicPrototype
, /*IsMasked=*/true, HasMaskedOffOperand
, HasVL
, NF
,
642 MaskedPolicyScheme
, DefaultPolicy
, IsTuple
);
644 // Create Intrinsics for each type and LMUL.
645 for (char I
: TypeRange
) {
646 for (int Log2LMUL
: Log2LMULList
) {
647 BasicType BT
= ParseBasicType(I
);
648 std::optional
<RVVTypes
> Types
=
649 TypeCache
.computeTypes(BT
, Log2LMUL
, NF
, Prototype
);
650 // Ignored to create new intrinsic if there are any illegal types.
655 RVVIntrinsic::getSuffixStr(TypeCache
, BT
, Log2LMUL
, SuffixDesc
);
656 auto OverloadedSuffixStr
= RVVIntrinsic::getSuffixStr(
657 TypeCache
, BT
, Log2LMUL
, OverloadedSuffixDesc
);
658 // Create a unmasked intrinsic
659 Out
.push_back(std::make_unique
<RVVIntrinsic
>(
660 Name
, SuffixStr
, OverloadedName
, OverloadedSuffixStr
, IRName
,
661 /*IsMasked=*/false, /*HasMaskedOffOperand=*/false, HasVL
,
662 UnMaskedPolicyScheme
, SupportOverloading
, HasBuiltinAlias
,
663 ManualCodegen
, *Types
, IntrinsicTypes
, NF
, DefaultPolicy
,
665 if (UnMaskedPolicyScheme
!= PolicyScheme::SchemeNone
)
666 for (auto P
: SupportedUnMaskedPolicies
) {
667 SmallVector
<PrototypeDescriptor
> PolicyPrototype
=
668 RVVIntrinsic::computeBuiltinTypes(
669 BasicPrototype
, /*IsMasked=*/false,
670 /*HasMaskedOffOperand=*/false, HasVL
, NF
,
671 UnMaskedPolicyScheme
, P
, IsTuple
);
672 std::optional
<RVVTypes
> PolicyTypes
=
673 TypeCache
.computeTypes(BT
, Log2LMUL
, NF
, PolicyPrototype
);
674 Out
.push_back(std::make_unique
<RVVIntrinsic
>(
675 Name
, SuffixStr
, OverloadedName
, OverloadedSuffixStr
, IRName
,
676 /*IsMask=*/false, /*HasMaskedOffOperand=*/false, HasVL
,
677 UnMaskedPolicyScheme
, SupportOverloading
, HasBuiltinAlias
,
678 ManualCodegen
, *PolicyTypes
, IntrinsicTypes
, NF
, P
,
683 // Create a masked intrinsic
684 std::optional
<RVVTypes
> MaskTypes
=
685 TypeCache
.computeTypes(BT
, Log2LMUL
, NF
, MaskedPrototype
);
686 Out
.push_back(std::make_unique
<RVVIntrinsic
>(
687 Name
, SuffixStr
, OverloadedName
, OverloadedSuffixStr
, MaskedIRName
,
688 /*IsMasked=*/true, HasMaskedOffOperand
, HasVL
, MaskedPolicyScheme
,
689 SupportOverloading
, HasBuiltinAlias
, ManualCodegen
, *MaskTypes
,
690 IntrinsicTypes
, NF
, DefaultPolicy
, HasFRMRoundModeOp
));
691 if (MaskedPolicyScheme
== PolicyScheme::SchemeNone
)
693 for (auto P
: SupportedMaskedPolicies
) {
694 SmallVector
<PrototypeDescriptor
> PolicyPrototype
=
695 RVVIntrinsic::computeBuiltinTypes(
696 BasicPrototype
, /*IsMasked=*/true, HasMaskedOffOperand
, HasVL
,
697 NF
, MaskedPolicyScheme
, P
, IsTuple
);
698 std::optional
<RVVTypes
> PolicyTypes
=
699 TypeCache
.computeTypes(BT
, Log2LMUL
, NF
, PolicyPrototype
);
700 Out
.push_back(std::make_unique
<RVVIntrinsic
>(
701 Name
, SuffixStr
, OverloadedName
, OverloadedSuffixStr
,
702 MaskedIRName
, /*IsMasked=*/true, HasMaskedOffOperand
, HasVL
,
703 MaskedPolicyScheme
, SupportOverloading
, HasBuiltinAlias
,
704 ManualCodegen
, *PolicyTypes
, IntrinsicTypes
, NF
, P
,
707 } // End for Log2LMULList
708 } // End for TypeRange
710 // We don't emit vsetvli and vsetvlimax for SemaRecord.
711 // They are written in riscv_vector.td and will emit those marco define in
713 if (Name
== "vsetvli" || Name
== "vsetvlimax")
721 SR
.Name
= Name
.str();
722 SR
.OverloadedName
= OverloadedName
.str();
723 BasicType TypeRangeMask
= BasicType::Unknown
;
724 for (char I
: TypeRange
)
725 TypeRangeMask
|= ParseBasicType(I
);
727 SR
.TypeRangeMask
= static_cast<unsigned>(TypeRangeMask
);
729 unsigned Log2LMULMask
= 0;
730 for (int Log2LMUL
: Log2LMULList
)
731 Log2LMULMask
|= 1 << (Log2LMUL
+ 3);
733 SR
.Log2LMULMask
= Log2LMULMask
;
735 SR
.RequiredExtensions
= 0;
736 for (auto RequiredFeature
: RequiredFeatures
) {
737 RVVRequire RequireExt
=
738 StringSwitch
<RVVRequire
>(RequiredFeature
)
739 .Case("RV64", RVV_REQ_RV64
)
740 .Case("Zvfhmin", RVV_REQ_Zvfhmin
)
741 .Case("Xsfvcp", RVV_REQ_Xsfvcp
)
742 .Case("Xsfvfnrclipxfqf", RVV_REQ_Xsfvfnrclipxfqf
)
743 .Case("Xsfvfwmaccqqq", RVV_REQ_Xsfvfwmaccqqq
)
744 .Case("Xsfvqmaccdod", RVV_REQ_Xsfvqmaccdod
)
745 .Case("Xsfvqmaccqoq", RVV_REQ_Xsfvqmaccqoq
)
746 .Case("Zvbb", RVV_REQ_Zvbb
)
747 .Case("Zvbc", RVV_REQ_Zvbc
)
748 .Case("Zvkb", RVV_REQ_Zvkb
)
749 .Case("Zvkg", RVV_REQ_Zvkg
)
750 .Case("Zvkned", RVV_REQ_Zvkned
)
751 .Case("Zvknha", RVV_REQ_Zvknha
)
752 .Case("Zvknhb", RVV_REQ_Zvknhb
)
753 .Case("Zvksed", RVV_REQ_Zvksed
)
754 .Case("Zvksh", RVV_REQ_Zvksh
)
755 .Case("Zvfbfwma", RVV_REQ_Zvfbfwma
)
756 .Case("Zvfbfmin", RVV_REQ_Zvfbfmin
)
757 .Case("Zvfh", RVV_REQ_Zvfh
)
758 .Case("Experimental", RVV_REQ_Experimental
)
759 .Default(RVV_REQ_None
);
760 assert(RequireExt
!= RVV_REQ_None
&& "Unrecognized required feature?");
761 SR
.RequiredExtensions
|= RequireExt
;
765 SR
.HasMasked
= HasMasked
;
767 SR
.HasMaskedOffOperand
= HasMaskedOffOperand
;
768 SR
.HasTailPolicy
= HasTailPolicy
;
769 SR
.HasMaskPolicy
= HasMaskPolicy
;
770 SR
.UnMaskedPolicyScheme
= static_cast<uint8_t>(UnMaskedPolicyScheme
);
771 SR
.MaskedPolicyScheme
= static_cast<uint8_t>(MaskedPolicyScheme
);
772 SR
.Prototype
= std::move(BasicPrototype
);
773 SR
.Suffix
= parsePrototypes(SuffixProto
);
774 SR
.OverloadedSuffix
= parsePrototypes(OverloadedSuffixProto
);
775 SR
.IsTuple
= IsTuple
;
776 SR
.HasFRMRoundModeOp
= HasFRMRoundModeOp
;
778 SemaRecords
->push_back(SR
);
782 void RVVEmitter::printHeaderCode(raw_ostream
&OS
) {
783 for (const Record
*R
: Records
.getAllDerivedDefinitions("RVVHeader")) {
784 StringRef HeaderCodeStr
= R
->getValueAsString("HeaderCode");
785 OS
<< HeaderCodeStr
.str();
789 void RVVEmitter::createRVVIntrinsicRecords(std::vector
<RVVIntrinsicRecord
> &Out
,
790 SemaSignatureTable
&SST
,
791 ArrayRef
<SemaRecord
> SemaRecords
) {
792 SST
.init(SemaRecords
);
794 for (const auto &SR
: SemaRecords
) {
795 Out
.emplace_back(RVVIntrinsicRecord());
796 RVVIntrinsicRecord
&R
= Out
.back();
797 R
.Name
= SR
.Name
.c_str();
798 R
.OverloadedName
= SR
.OverloadedName
.c_str();
799 R
.PrototypeIndex
= SST
.getIndex(SR
.Prototype
);
800 R
.SuffixIndex
= SST
.getIndex(SR
.Suffix
);
801 R
.OverloadedSuffixIndex
= SST
.getIndex(SR
.OverloadedSuffix
);
802 R
.PrototypeLength
= SR
.Prototype
.size();
803 R
.SuffixLength
= SR
.Suffix
.size();
804 R
.OverloadedSuffixSize
= SR
.OverloadedSuffix
.size();
805 R
.RequiredExtensions
= SR
.RequiredExtensions
;
806 R
.TypeRangeMask
= SR
.TypeRangeMask
;
807 R
.Log2LMULMask
= SR
.Log2LMULMask
;
809 R
.HasMasked
= SR
.HasMasked
;
811 R
.HasMaskedOffOperand
= SR
.HasMaskedOffOperand
;
812 R
.HasTailPolicy
= SR
.HasTailPolicy
;
813 R
.HasMaskPolicy
= SR
.HasMaskPolicy
;
814 R
.UnMaskedPolicyScheme
= SR
.UnMaskedPolicyScheme
;
815 R
.MaskedPolicyScheme
= SR
.MaskedPolicyScheme
;
816 R
.IsTuple
= SR
.IsTuple
;
817 R
.HasFRMRoundModeOp
= SR
.HasFRMRoundModeOp
;
819 assert(R
.PrototypeIndex
!=
820 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX
));
821 assert(R
.SuffixIndex
!=
822 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX
));
823 assert(R
.OverloadedSuffixIndex
!=
824 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX
));
828 void RVVEmitter::createSema(raw_ostream
&OS
) {
829 std::vector
<std::unique_ptr
<RVVIntrinsic
>> Defs
;
830 std::vector
<RVVIntrinsicRecord
> RVVIntrinsicRecords
;
831 SemaSignatureTable SST
;
832 std::vector
<SemaRecord
> SemaRecords
;
834 createRVVIntrinsics(Defs
, &SemaRecords
);
836 createRVVIntrinsicRecords(RVVIntrinsicRecords
, SST
, SemaRecords
);
838 // Emit signature table for SemaRISCVVectorLookup.cpp.
839 OS
<< "#ifdef DECL_SIGNATURE_TABLE\n";
843 // Emit RVVIntrinsicRecords for SemaRISCVVectorLookup.cpp.
844 OS
<< "#ifdef DECL_INTRINSIC_RECORDS\n";
845 for (const RVVIntrinsicRecord
&Record
: RVVIntrinsicRecords
)
851 void EmitRVVHeader(const RecordKeeper
&Records
, raw_ostream
&OS
) {
852 RVVEmitter(Records
).createHeader(OS
);
855 void EmitRVVBuiltins(const RecordKeeper
&Records
, raw_ostream
&OS
) {
856 RVVEmitter(Records
).createBuiltins(OS
);
859 void EmitRVVBuiltinCG(const RecordKeeper
&Records
, raw_ostream
&OS
) {
860 RVVEmitter(Records
).createCodeGen(OS
);
863 void EmitRVVBuiltinSema(const RecordKeeper
&Records
, raw_ostream
&OS
) {
864 RVVEmitter(Records
).createSema(OS
);
867 } // End namespace clang