881 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This tablegen backend is responsible for emitting riscv_vector.h which10// includes a declaration and definition of each intrinsic functions specified11// 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/StringExtras.h"20#include "llvm/ADT/StringMap.h"21#include "llvm/ADT/StringRef.h"22#include "llvm/ADT/StringSwitch.h"23#include "llvm/ADT/Twine.h"24#include "llvm/TableGen/Error.h"25#include "llvm/TableGen/Record.h"26#include "llvm/TableGen/StringToOffsetTable.h"27#include <optional>28 29using namespace llvm;30using namespace clang::RISCV;31 32namespace {33struct SemaRecord {34 // Intrinsic name, e.g. vadd_vv35 std::string Name;36 37 // Overloaded intrinsic name, could be empty if can be computed from Name38 // e.g. vadd39 std::string OverloadedName;40 41 // Supported type, mask of BasicType.42 unsigned TypeRangeMask;43 44 // Supported LMUL.45 unsigned Log2LMULMask;46 47 // Required extensions for this intrinsic.48 std::string RequiredExtensions;49 50 // Prototype for this intrinsic.51 SmallVector<PrototypeDescriptor> Prototype;52 53 // Suffix of intrinsic name.54 SmallVector<PrototypeDescriptor> Suffix;55 56 // Suffix of overloaded intrinsic name.57 SmallVector<PrototypeDescriptor> OverloadedSuffix;58 59 // Number of field, large than 1 if it's segment load/store.60 unsigned NF;61 62 bool HasMasked :1;63 bool HasVL :1;64 bool HasMaskedOffOperand :1;65 bool HasTailPolicy : 1;66 bool HasMaskPolicy : 1;67 bool HasFRMRoundModeOp : 1;68 bool IsTuple : 1;69 LLVM_PREFERRED_TYPE(PolicyScheme)70 uint8_t UnMaskedPolicyScheme : 2;71 LLVM_PREFERRED_TYPE(PolicyScheme)72 uint8_t MaskedPolicyScheme : 2;73};74 75// Compressed function signature table.76class SemaSignatureTable {77private:78 std::vector<PrototypeDescriptor> SignatureTable;79 80 void insert(ArrayRef<PrototypeDescriptor> Signature);81 82public:83 static constexpr unsigned INVALID_INDEX = ~0U;84 85 // Create compressed signature table from SemaRecords.86 void init(ArrayRef<SemaRecord> SemaRecords);87 88 // Query the Signature, return INVALID_INDEX if not found.89 unsigned getIndex(ArrayRef<PrototypeDescriptor> Signature);90 91 /// Print signature table in RVVHeader Record to \p OS92 void print(raw_ostream &OS);93};94 95class RVVEmitter {96private:97 const RecordKeeper &Records;98 RVVTypeCache TypeCache;99 100public:101 RVVEmitter(const RecordKeeper &R) : Records(R) {}102 103 /// Emit riscv_vector.h104 void createHeader(raw_ostream &o);105 106 /// Emit all the __builtin prototypes and code needed by Sema.107 void createBuiltins(raw_ostream &o);108 109 /// Emit all the information needed to map builtin -> LLVM IR intrinsic.110 void createCodeGen(raw_ostream &o);111 112 /// Emit all the information needed by SemaRISCVVectorLookup.cpp.113 /// We've large number of intrinsic function for RVV, creating a customized114 /// could speed up the compilation time.115 void createSema(raw_ostream &o);116 117private:118 /// Create all intrinsics and add them to \p Out and SemaRecords.119 void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out,120 std::vector<SemaRecord> *SemaRecords = nullptr);121 /// Create all intrinsic records and SemaSignatureTable from SemaRecords.122 void createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out,123 SemaSignatureTable &SST,124 ArrayRef<SemaRecord> SemaRecords);125 126 /// Print HeaderCode in RVVHeader Record to \p Out127 void printHeaderCode(raw_ostream &OS);128};129 130} // namespace131 132static BasicType ParseBasicType(char c) {133 switch (c) {134 case 'c':135 return BasicType::Int8;136 case 's':137 return BasicType::Int16;138 case 'i':139 return BasicType::Int32;140 case 'l':141 return BasicType::Int64;142 case 'x':143 return BasicType::Float16;144 case 'f':145 return BasicType::Float32;146 case 'd':147 return BasicType::Float64;148 case 'y':149 return BasicType::BFloat16;150 default:151 return BasicType::Unknown;152 }153}154 155static VectorTypeModifier getTupleVTM(unsigned NF) {156 assert(2 <= NF && NF <= 8 && "2 <= NF <= 8");157 return static_cast<VectorTypeModifier>(158 static_cast<uint8_t>(VectorTypeModifier::Tuple2) + (NF - 2));159}160 161static const unsigned UnknownIndex = (unsigned)-1;162 163static unsigned getIndexedLoadStorePtrIdx(const RVVIntrinsic *RVVI) {164 // We need a special rule for segment load/store since the data width is not165 // encoded in the intrinsic name itself.166 const StringRef IRName = RVVI->getIRName();167 constexpr unsigned RVV_VTA = 0x1;168 constexpr unsigned RVV_VMA = 0x2;169 170 if (IRName.starts_with("vloxseg") || IRName.starts_with("vluxseg")) {171 bool NoPassthru =172 (RVVI->isMasked() && (RVVI->getPolicyAttrsBits() & RVV_VTA) &&173 (RVVI->getPolicyAttrsBits() & RVV_VMA)) ||174 (!RVVI->isMasked() && (RVVI->getPolicyAttrsBits() & RVV_VTA));175 return RVVI->isMasked() ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1;176 }177 if (IRName.starts_with("vsoxseg") || IRName.starts_with("vsuxseg"))178 return RVVI->isMasked() ? 1 : 0;179 180 return UnknownIndex;181}182 183// This function is used to get the log2SEW of each segment load/store, this184// prevent to add a member to RVVIntrinsic.185static unsigned getSegInstLog2SEW(StringRef InstName) {186 // clang-format off187 // We need a special rule for indexed segment load/store since the data width188 // is not encoded in the intrinsic name itself.189 if (InstName.starts_with("vloxseg") || InstName.starts_with("vluxseg") ||190 InstName.starts_with("vsoxseg") || InstName.starts_with("vsuxseg"))191 return (unsigned)-1;192 193#define KEY_VAL(KEY, VAL) {#KEY, VAL}194#define KEY_VAL_ALL_W_POLICY(KEY, VAL) \195 KEY_VAL(KEY, VAL), \196 KEY_VAL(KEY ## _tu, VAL), \197 KEY_VAL(KEY ## _tum, VAL), \198 KEY_VAL(KEY ## _tumu, VAL), \199 KEY_VAL(KEY ## _mu, VAL)200 201#define KEY_VAL_ALL_NF_BASE(MACRO_NAME, NAME, SEW, LOG2SEW, FF) \202 MACRO_NAME(NAME ## 2e ## SEW ## FF, LOG2SEW), \203 MACRO_NAME(NAME ## 3e ## SEW ## FF, LOG2SEW), \204 MACRO_NAME(NAME ## 4e ## SEW ## FF, LOG2SEW), \205 MACRO_NAME(NAME ## 5e ## SEW ## FF, LOG2SEW), \206 MACRO_NAME(NAME ## 6e ## SEW ## FF, LOG2SEW), \207 MACRO_NAME(NAME ## 7e ## SEW ## FF, LOG2SEW), \208 MACRO_NAME(NAME ## 8e ## SEW ## FF, LOG2SEW)209 210#define KEY_VAL_ALL_NF(NAME, SEW, LOG2SEW) \211 KEY_VAL_ALL_NF_BASE(KEY_VAL_ALL_W_POLICY, NAME, SEW, LOG2SEW,)212 213#define KEY_VAL_FF_ALL_NF(NAME, SEW, LOG2SEW) \214 KEY_VAL_ALL_NF_BASE(KEY_VAL_ALL_W_POLICY, NAME, SEW, LOG2SEW, ff)215 216#define KEY_VAL_ALL_NF_SEW_BASE(MACRO_NAME, NAME) \217 MACRO_NAME(NAME, 8, 3), \218 MACRO_NAME(NAME, 16, 4), \219 MACRO_NAME(NAME, 32, 5), \220 MACRO_NAME(NAME, 64, 6)221 222#define KEY_VAL_ALL_NF_SEW(NAME) \223 KEY_VAL_ALL_NF_SEW_BASE(KEY_VAL_ALL_NF, NAME)224 225#define KEY_VAL_FF_ALL_NF_SEW(NAME) \226 KEY_VAL_ALL_NF_SEW_BASE(KEY_VAL_FF_ALL_NF, NAME)227 // clang-format on228 229 static StringMap<unsigned> SegInsts = {230 KEY_VAL_ALL_NF_SEW(vlseg), KEY_VAL_FF_ALL_NF_SEW(vlseg),231 KEY_VAL_ALL_NF_SEW(vlsseg), KEY_VAL_ALL_NF_SEW(vsseg),232 KEY_VAL_ALL_NF_SEW(vssseg)};233 234#undef KEY_VAL_ALL_NF_SEW235#undef KEY_VAL_ALL_NF236#undef KEY_VAL237 238 return SegInsts.lookup(InstName);239}240 241void emitCodeGenSwitchBody(const RVVIntrinsic *RVVI, raw_ostream &OS) {242 if (!RVVI->getIRName().empty())243 OS << " ID = Intrinsic::riscv_" + RVVI->getIRName() + ";\n";244 if (RVVI->getTWiden() > 0)245 OS << " TWiden = " << RVVI->getTWiden() << ";\n";246 247 OS << " PolicyAttrs = " << RVVI->getPolicyAttrsBits() << ";\n";248 unsigned IndexedLoadStorePtrIdx = getIndexedLoadStorePtrIdx(RVVI);249 if (IndexedLoadStorePtrIdx != UnknownIndex) {250 OS << " {\n";251 OS << " auto PointeeType = E->getArg(" << IndexedLoadStorePtrIdx252 << ")->getType()->getPointeeType();\n";253 OS << " SegInstSEW = "254 "llvm::Log2_64(getContext().getTypeSize(PointeeType));\n";255 OS << " }\n";256 } else {257 OS << " SegInstSEW = " << getSegInstLog2SEW(RVVI->getOverloadedName())258 << ";\n";259 }260 261 if (RVVI->hasManualCodegen()) {262 OS << "IsMasked = " << (RVVI->isMasked() ? "true" : "false") << ";\n";263 OS << RVVI->getManualCodegen();264 OS << "break;\n";265 return;266 }267 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.");272 }273 }274 275 if (RVVI->isMasked()) {276 if (RVVI->hasVL()) {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(),"280 " PolicyAttrs));\n";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";289 } else {290 OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n";291 }292 } else {293 if (RVVI->hasPolicyOperand())294 OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(), "295 "PolicyAttrs));\n";296 else if (RVVI->hasPassthruOperand() && RVVI->getPolicyAttrs().isTAPolicy())297 OS << " Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));\n";298 }299 300 if (RVVI->getTWiden() > 0)301 OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(), TWiden));\n";302 303 OS << " IntrinsicTypes = {";304 ListSeparator LS;305 for (const auto &Idx : RVVI->getIntrinsicTypes()) {306 if (Idx == -1)307 OS << LS << "ResultType";308 else309 OS << LS << "Ops[" << Idx << "]->getType()";310 }311 312 // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is313 // always last operand.314 if (RVVI->hasVL())315 OS << ", Ops.back()->getType()";316 OS << "};\n";317 OS << " break;\n";318}319 320//===----------------------------------------------------------------------===//321// SemaSignatureTable implementation322//===----------------------------------------------------------------------===//323void SemaSignatureTable::init(ArrayRef<SemaRecord> SemaRecords) {324 // Sort signature entries by length, let longer signature insert first, to325 // make it more possible to reuse table entries, that can reduce ~10% table326 // size.327 struct Compare {328 bool operator()(const SmallVector<PrototypeDescriptor> &A,329 const SmallVector<PrototypeDescriptor> &B) const {330 if (A.size() != B.size())331 return A.size() > B.size();332 333 size_t Len = A.size();334 for (size_t i = 0; i < Len; ++i) {335 if (A[i] != B[i])336 return A[i] < B[i];337 }338 339 return false;340 }341 };342 343 std::set<SmallVector<PrototypeDescriptor>, Compare> Signatures;344 auto InsertToSignatureSet =345 [&](const SmallVector<PrototypeDescriptor> &Signature) {346 if (Signature.empty())347 return;348 349 Signatures.insert(Signature);350 };351 352 assert(!SemaRecords.empty());353 354 for (const SemaRecord &SR : SemaRecords) {355 InsertToSignatureSet(SR.Prototype);356 InsertToSignatureSet(SR.Suffix);357 InsertToSignatureSet(SR.OverloadedSuffix);358 }359 360 for (auto &Sig : Signatures)361 insert(Sig);362}363 364void SemaSignatureTable::insert(ArrayRef<PrototypeDescriptor> Signature) {365 if (getIndex(Signature) != INVALID_INDEX)366 return;367 368 // Insert Signature into SignatureTable if not found in the table.369 SignatureTable.insert(SignatureTable.begin(), Signature.begin(),370 Signature.end());371}372 373unsigned SemaSignatureTable::getIndex(ArrayRef<PrototypeDescriptor> Signature) {374 // Empty signature could be point into any index since there is length375 // field when we use, so just always point it to 0.376 if (Signature.empty())377 return 0;378 379 // Checking Signature already in table or not.380 if (Signature.size() <= SignatureTable.size()) {381 size_t Bound = SignatureTable.size() - Signature.size() + 1;382 for (size_t Index = 0; Index < Bound; ++Index) {383 if (equal(Signature.begin(), Signature.end(),384 SignatureTable.begin() + Index))385 return Index;386 }387 }388 389 return INVALID_INDEX;390}391 392void SemaSignatureTable::print(raw_ostream &OS) {393 for (const auto &Sig : SignatureTable)394 OS << "PrototypeDescriptor(" << static_cast<int>(Sig.PT) << ", "395 << static_cast<int>(Sig.VTM) << ", " << static_cast<int>(Sig.TM)396 << "),\n";397}398 399//===----------------------------------------------------------------------===//400// RVVEmitter implementation401//===----------------------------------------------------------------------===//402void RVVEmitter::createHeader(raw_ostream &OS) {403 404 OS << "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics "405 "-------------------===\n"406 " *\n"407 " *\n"408 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "409 "Exceptions.\n"410 " * See https://llvm.org/LICENSE.txt for license information.\n"411 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"412 " *\n"413 " *===-----------------------------------------------------------------"414 "------===\n"415 " */\n\n";416 417 OS << "#ifndef __RISCV_VECTOR_H\n";418 OS << "#define __RISCV_VECTOR_H\n\n";419 420 OS << "#include <stdint.h>\n";421 OS << "#include <stddef.h>\n\n";422 423 OS << "#ifdef __cplusplus\n";424 OS << "extern \"C\" {\n";425 OS << "#endif\n\n";426 427 OS << "#pragma clang riscv intrinsic vector\n\n";428 429 printHeaderCode(OS);430 431 auto printType = [&](auto T) {432 OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr()433 << ";\n";434 };435 436 constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3};437 // Print RVV boolean types.438 for (int Log2LMUL : Log2LMULs) {439 auto T = TypeCache.computeType(BasicType::Int8, Log2LMUL,440 PrototypeDescriptor::Mask);441 if (T)442 printType(*T);443 }444 // Print RVV int/float types.445 for (char I : StringRef("csil")) {446 BasicType BT = ParseBasicType(I);447 for (int Log2LMUL : Log2LMULs) {448 auto T = TypeCache.computeType(BT, Log2LMUL, PrototypeDescriptor::Vector);449 if (T) {450 printType(*T);451 auto UT = TypeCache.computeType(452 BT, Log2LMUL,453 PrototypeDescriptor(BaseTypeModifier::Vector,454 VectorTypeModifier::NoModifier,455 TypeModifier::UnsignedInteger));456 printType(*UT);457 }458 for (int NF = 2; NF <= 8; ++NF) {459 auto TupleT = TypeCache.computeType(460 BT, Log2LMUL,461 PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF),462 TypeModifier::SignedInteger));463 auto TupleUT = TypeCache.computeType(464 BT, Log2LMUL,465 PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF),466 TypeModifier::UnsignedInteger));467 if (TupleT)468 printType(*TupleT);469 if (TupleUT)470 printType(*TupleUT);471 }472 }473 }474 475 for (BasicType BT : {BasicType::Float16, BasicType::Float32,476 BasicType::Float64, BasicType::BFloat16}) {477 for (int Log2LMUL : Log2LMULs) {478 auto T = TypeCache.computeType(BT, Log2LMUL, PrototypeDescriptor::Vector);479 if (T)480 printType(*T);481 for (int NF = 2; NF <= 8; ++NF) {482 auto TupleT = TypeCache.computeType(483 BT, Log2LMUL,484 PrototypeDescriptor(BaseTypeModifier::Vector, getTupleVTM(NF),485 (BT == BasicType::BFloat16486 ? TypeModifier::BFloat487 : TypeModifier::Float)));488 if (TupleT)489 printType(*TupleT);490 }491 }492 }493 494 OS << "\n#ifdef __cplusplus\n";495 OS << "}\n";496 OS << "#endif // __cplusplus\n";497 OS << "#endif // __RISCV_VECTOR_H\n";498}499 500void RVVEmitter::createBuiltins(raw_ostream &OS) {501 std::vector<std::unique_ptr<RVVIntrinsic>> Defs;502 createRVVIntrinsics(Defs);503 504 llvm::StringToOffsetTable Table;505 // Ensure offset zero is the empty string.506 Table.GetOrAddStringOffset("");507 // Hard coded strings used in the builtin structures.508 Table.GetOrAddStringOffset("n");509 Table.GetOrAddStringOffset("zve32x");510 511 // Map to unique the builtin names.512 StringMap<RVVIntrinsic *> BuiltinMap;513 std::vector<RVVIntrinsic *> UniqueDefs;514 for (auto &Def : Defs) {515 auto P = BuiltinMap.insert({Def->getBuiltinName(), Def.get()});516 if (P.second) {517 Table.GetOrAddStringOffset(Def->getBuiltinName());518 if (!Def->hasBuiltinAlias())519 Table.GetOrAddStringOffset(Def->getBuiltinTypeStr());520 UniqueDefs.push_back(Def.get());521 continue;522 }523 524 // Verf that this would have produced the same builtin definition.525 if (P.first->second->hasBuiltinAlias() != Def->hasBuiltinAlias())526 PrintFatalError("Builtin with same name has different hasAutoDef");527 else if (!Def->hasBuiltinAlias() &&528 P.first->second->getBuiltinTypeStr() != Def->getBuiltinTypeStr())529 PrintFatalError("Builtin with same name has different type string");530 }531 532 // Emit the enumerators of RVV builtins. Note that these are emitted without533 // any outer context to enable concatenating them.534 OS << "// RISCV Vector builtin enumerators\n";535 OS << "#ifdef GET_RISCVV_BUILTIN_ENUMERATORS\n";536 for (RVVIntrinsic *Def : UniqueDefs)537 OS << " BI__builtin_rvv_" << Def->getBuiltinName() << ",\n";538 OS << "#endif // GET_RISCVV_BUILTIN_ENUMERATORS\n\n";539 540 // Emit the string table for the RVV builtins.541 OS << "// RISCV Vector builtin enumerators\n";542 OS << "#ifdef GET_RISCVV_BUILTIN_STR_TABLE\n";543 Table.EmitStringTableDef(OS, "BuiltinStrings");544 OS << "#endif // GET_RISCVV_BUILTIN_STR_TABLE\n\n";545 546 // Emit the info structs of RVV builtins. Note that these are emitted without547 // any outer context to enable concatenating them.548 OS << "// RISCV Vector builtin infos\n";549 OS << "#ifdef GET_RISCVV_BUILTIN_INFOS\n";550 for (RVVIntrinsic *Def : UniqueDefs) {551 OS << " Builtin::Info{Builtin::Info::StrOffsets{"552 << Table.GetStringOffset(Def->getBuiltinName()) << " /* "553 << Def->getBuiltinName() << " */, ";554 if (Def->hasBuiltinAlias()) {555 OS << "0, ";556 } else {557 OS << Table.GetStringOffset(Def->getBuiltinTypeStr()) << " /* "558 << Def->getBuiltinTypeStr() << " */, ";559 }560 OS << Table.GetStringOffset("n") << " /* n */, ";561 OS << Table.GetStringOffset("zve32x") << " /* zve32x */}, ";562 563 OS << "HeaderDesc::NO_HEADER, ALL_LANGUAGES},\n";564 }565 OS << "#endif // GET_RISCVV_BUILTIN_INFOS\n\n";566}567 568void RVVEmitter::createCodeGen(raw_ostream &OS) {569 std::vector<std::unique_ptr<RVVIntrinsic>> Defs;570 createRVVIntrinsics(Defs);571 // IR name could be empty, use the stable sort preserves the relative order.572 stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A,573 const std::unique_ptr<RVVIntrinsic> &B) {574 if (A->getIRName() == B->getIRName())575 return (A->getPolicyAttrs() < B->getPolicyAttrs());576 return (A->getIRName() < B->getIRName());577 });578 579 // Map to keep track of which builtin names have already been emitted.580 StringMap<RVVIntrinsic *> BuiltinMap;581 582 // Print switch body when the ir name, ManualCodegen, policy or log2sew583 // changes from previous iteration.584 RVVIntrinsic *PrevDef = Defs.begin()->get();585 for (auto &Def : Defs) {586 StringRef CurIRName = Def->getIRName();587 if (CurIRName != PrevDef->getIRName() ||588 (Def->getManualCodegen() != PrevDef->getManualCodegen()) ||589 (Def->getPolicyAttrs() != PrevDef->getPolicyAttrs()) ||590 (getSegInstLog2SEW(Def->getOverloadedName()) !=591 getSegInstLog2SEW(PrevDef->getOverloadedName())) ||592 (Def->getTWiden() != PrevDef->getTWiden())) {593 emitCodeGenSwitchBody(PrevDef, OS);594 }595 PrevDef = Def.get();596 597 auto P =598 BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get()));599 if (P.second) {600 OS << "case RISCVVector::BI__builtin_rvv_" << Def->getBuiltinName()601 << ":\n";602 continue;603 }604 605 if (P.first->second->getIRName() != Def->getIRName())606 PrintFatalError("Builtin with same name has different IRName");607 else if (P.first->second->getManualCodegen() != Def->getManualCodegen())608 PrintFatalError("Builtin with same name has different ManualCodegen");609 else if (P.first->second->isMasked() != Def->isMasked())610 PrintFatalError("Builtin with same name has different isMasked");611 else if (P.first->second->hasVL() != Def->hasVL())612 PrintFatalError("Builtin with same name has different hasVL");613 else if (P.first->second->getPolicyScheme() != Def->getPolicyScheme())614 PrintFatalError("Builtin with same name has different getPolicyScheme");615 else if (P.first->second->getIntrinsicTypes() != Def->getIntrinsicTypes())616 PrintFatalError("Builtin with same name has different IntrinsicTypes");617 }618 emitCodeGenSwitchBody(Defs.back().get(), OS);619 OS << "\n";620}621 622void RVVEmitter::createRVVIntrinsics(623 std::vector<std::unique_ptr<RVVIntrinsic>> &Out,624 std::vector<SemaRecord> *SemaRecords) {625 for (const Record *R : Records.getAllDerivedDefinitions("RVVBuiltin")) {626 StringRef Name = R->getValueAsString("Name");627 StringRef SuffixProto = R->getValueAsString("Suffix");628 StringRef OverloadedName = R->getValueAsString("OverloadedName");629 StringRef OverloadedSuffixProto = R->getValueAsString("OverloadedSuffix");630 StringRef Prototypes = R->getValueAsString("Prototype");631 StringRef TypeRange = R->getValueAsString("TypeRange");632 bool HasMasked = R->getValueAsBit("HasMasked");633 bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand");634 bool HasVL = R->getValueAsBit("HasVL");635 const Record *MPSRecord = R->getValueAsDef("MaskedPolicyScheme");636 auto MaskedPolicyScheme =637 static_cast<PolicyScheme>(MPSRecord->getValueAsInt("Value"));638 const Record *UMPSRecord = R->getValueAsDef("UnMaskedPolicyScheme");639 auto UnMaskedPolicyScheme =640 static_cast<PolicyScheme>(UMPSRecord->getValueAsInt("Value"));641 std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL");642 bool HasTailPolicy = R->getValueAsBit("HasTailPolicy");643 bool HasMaskPolicy = R->getValueAsBit("HasMaskPolicy");644 bool SupportOverloading = R->getValueAsBit("SupportOverloading");645 bool HasBuiltinAlias = R->getValueAsBit("HasBuiltinAlias");646 StringRef ManualCodegen = R->getValueAsString("ManualCodegen");647 std::vector<int64_t> IntrinsicTypes =648 R->getValueAsListOfInts("IntrinsicTypes");649 std::vector<StringRef> RequiredFeatures =650 R->getValueAsListOfStrings("RequiredFeatures");651 StringRef IRName = R->getValueAsString("IRName");652 StringRef MaskedIRName = R->getValueAsString("MaskedIRName");653 unsigned NF = R->getValueAsInt("NF");654 unsigned TWiden = R->getValueAsInt("TWiden");655 bool IsTuple = R->getValueAsBit("IsTuple");656 bool HasFRMRoundModeOp = R->getValueAsBit("HasFRMRoundModeOp");657 658 const Policy DefaultPolicy;659 SmallVector<Policy> SupportedUnMaskedPolicies =660 RVVIntrinsic::getSupportedUnMaskedPolicies();661 SmallVector<Policy> SupportedMaskedPolicies =662 RVVIntrinsic::getSupportedMaskedPolicies(HasTailPolicy, HasMaskPolicy);663 664 // Parse prototype and create a list of primitive type with transformers665 // (operand) in Prototype. Prototype[0] is output operand.666 SmallVector<PrototypeDescriptor> BasicPrototype =667 parsePrototypes(Prototypes);668 669 SmallVector<PrototypeDescriptor> SuffixDesc = parsePrototypes(SuffixProto);670 SmallVector<PrototypeDescriptor> OverloadedSuffixDesc =671 parsePrototypes(OverloadedSuffixProto);672 673 // Compute Builtin types674 auto Prototype = RVVIntrinsic::computeBuiltinTypes(675 BasicPrototype, /*IsMasked=*/false,676 /*HasMaskedOffOperand=*/false, HasVL, NF, UnMaskedPolicyScheme,677 DefaultPolicy, IsTuple);678 SmallVector<PrototypeDescriptor> MaskedPrototype;679 if (HasMasked)680 MaskedPrototype = RVVIntrinsic::computeBuiltinTypes(681 BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL, NF,682 MaskedPolicyScheme, DefaultPolicy, IsTuple);683 684 // Create Intrinsics for each type and LMUL.685 for (char I : TypeRange) {686 for (int Log2LMUL : Log2LMULList) {687 BasicType BT = ParseBasicType(I);688 std::optional<RVVTypes> Types =689 TypeCache.computeTypes(BT, Log2LMUL, NF, Prototype);690 // Ignored to create new intrinsic if there are any illegal types.691 if (!Types)692 continue;693 694 auto SuffixStr =695 RVVIntrinsic::getSuffixStr(TypeCache, BT, Log2LMUL, SuffixDesc);696 auto OverloadedSuffixStr = RVVIntrinsic::getSuffixStr(697 TypeCache, BT, Log2LMUL, OverloadedSuffixDesc);698 // Create a unmasked intrinsic699 Out.push_back(std::make_unique<RVVIntrinsic>(700 Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName,701 /*IsMasked=*/false, /*HasMaskedOffOperand=*/false, HasVL,702 UnMaskedPolicyScheme, SupportOverloading, HasBuiltinAlias,703 ManualCodegen, *Types, IntrinsicTypes, NF, DefaultPolicy,704 HasFRMRoundModeOp, TWiden));705 if (UnMaskedPolicyScheme != PolicyScheme::SchemeNone)706 for (auto P : SupportedUnMaskedPolicies) {707 SmallVector<PrototypeDescriptor> PolicyPrototype =708 RVVIntrinsic::computeBuiltinTypes(709 BasicPrototype, /*IsMasked=*/false,710 /*HasMaskedOffOperand=*/false, HasVL, NF,711 UnMaskedPolicyScheme, P, IsTuple);712 std::optional<RVVTypes> PolicyTypes =713 TypeCache.computeTypes(BT, Log2LMUL, NF, PolicyPrototype);714 Out.push_back(std::make_unique<RVVIntrinsic>(715 Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName,716 /*IsMask=*/false, /*HasMaskedOffOperand=*/false, HasVL,717 UnMaskedPolicyScheme, SupportOverloading, HasBuiltinAlias,718 ManualCodegen, *PolicyTypes, IntrinsicTypes, NF, P,719 HasFRMRoundModeOp, TWiden));720 }721 if (!HasMasked)722 continue;723 // Create a masked intrinsic724 std::optional<RVVTypes> MaskTypes =725 TypeCache.computeTypes(BT, Log2LMUL, NF, MaskedPrototype);726 Out.push_back(std::make_unique<RVVIntrinsic>(727 Name, SuffixStr, OverloadedName, OverloadedSuffixStr, MaskedIRName,728 /*IsMasked=*/true, HasMaskedOffOperand, HasVL, MaskedPolicyScheme,729 SupportOverloading, HasBuiltinAlias, ManualCodegen, *MaskTypes,730 IntrinsicTypes, NF, DefaultPolicy, HasFRMRoundModeOp, TWiden));731 if (MaskedPolicyScheme == PolicyScheme::SchemeNone)732 continue;733 for (auto P : SupportedMaskedPolicies) {734 SmallVector<PrototypeDescriptor> PolicyPrototype =735 RVVIntrinsic::computeBuiltinTypes(736 BasicPrototype, /*IsMasked=*/true, HasMaskedOffOperand, HasVL,737 NF, MaskedPolicyScheme, P, IsTuple);738 std::optional<RVVTypes> PolicyTypes =739 TypeCache.computeTypes(BT, Log2LMUL, NF, PolicyPrototype);740 Out.push_back(std::make_unique<RVVIntrinsic>(741 Name, SuffixStr, OverloadedName, OverloadedSuffixStr,742 MaskedIRName, /*IsMasked=*/true, HasMaskedOffOperand, HasVL,743 MaskedPolicyScheme, SupportOverloading, HasBuiltinAlias,744 ManualCodegen, *PolicyTypes, IntrinsicTypes, NF, P,745 HasFRMRoundModeOp, TWiden));746 }747 } // End for Log2LMULList748 } // End for TypeRange749 750 // We don't emit vsetvli and vsetvlimax for SemaRecord.751 // They are written in riscv_vector.td and will emit those marco define in752 // riscv_vector.h753 if (Name == "vsetvli" || Name == "vsetvlimax")754 continue;755 756 if (!SemaRecords)757 continue;758 759 // Create SemaRecord760 SemaRecord SR;761 SR.Name = Name.str();762 SR.OverloadedName = OverloadedName.str();763 BasicType TypeRangeMask = BasicType::Unknown;764 for (char I : TypeRange)765 TypeRangeMask |= ParseBasicType(I);766 767 SR.TypeRangeMask = static_cast<unsigned>(TypeRangeMask);768 769 unsigned Log2LMULMask = 0;770 for (int Log2LMUL : Log2LMULList)771 Log2LMULMask |= 1 << (Log2LMUL + 3);772 773 SR.Log2LMULMask = Log2LMULMask;774 std::string RFs =775 join(RequiredFeatures.begin(), RequiredFeatures.end(), ",");776 SR.RequiredExtensions = RFs;777 SR.NF = NF;778 SR.HasMasked = HasMasked;779 SR.HasVL = HasVL;780 SR.HasMaskedOffOperand = HasMaskedOffOperand;781 SR.HasTailPolicy = HasTailPolicy;782 SR.HasMaskPolicy = HasMaskPolicy;783 SR.UnMaskedPolicyScheme = static_cast<uint8_t>(UnMaskedPolicyScheme);784 SR.MaskedPolicyScheme = static_cast<uint8_t>(MaskedPolicyScheme);785 SR.Prototype = std::move(BasicPrototype);786 SR.Suffix = parsePrototypes(SuffixProto);787 SR.OverloadedSuffix = parsePrototypes(OverloadedSuffixProto);788 SR.IsTuple = IsTuple;789 SR.HasFRMRoundModeOp = HasFRMRoundModeOp;790 791 SemaRecords->push_back(SR);792 }793}794 795void RVVEmitter::printHeaderCode(raw_ostream &OS) {796 for (const Record *R : Records.getAllDerivedDefinitions("RVVHeader")) {797 StringRef HeaderCodeStr = R->getValueAsString("HeaderCode");798 OS << HeaderCodeStr.str();799 }800}801 802void RVVEmitter::createRVVIntrinsicRecords(std::vector<RVVIntrinsicRecord> &Out,803 SemaSignatureTable &SST,804 ArrayRef<SemaRecord> SemaRecords) {805 SST.init(SemaRecords);806 807 for (const auto &SR : SemaRecords) {808 Out.emplace_back(RVVIntrinsicRecord());809 RVVIntrinsicRecord &R = Out.back();810 R.Name = SR.Name.c_str();811 R.OverloadedName = SR.OverloadedName.c_str();812 R.PrototypeIndex = SST.getIndex(SR.Prototype);813 R.SuffixIndex = SST.getIndex(SR.Suffix);814 R.OverloadedSuffixIndex = SST.getIndex(SR.OverloadedSuffix);815 R.PrototypeLength = SR.Prototype.size();816 R.SuffixLength = SR.Suffix.size();817 R.OverloadedSuffixSize = SR.OverloadedSuffix.size();818 R.RequiredExtensions = SR.RequiredExtensions.c_str();819 R.TypeRangeMask = SR.TypeRangeMask;820 R.Log2LMULMask = SR.Log2LMULMask;821 R.NF = SR.NF;822 R.HasMasked = SR.HasMasked;823 R.HasVL = SR.HasVL;824 R.HasMaskedOffOperand = SR.HasMaskedOffOperand;825 R.HasTailPolicy = SR.HasTailPolicy;826 R.HasMaskPolicy = SR.HasMaskPolicy;827 R.UnMaskedPolicyScheme = SR.UnMaskedPolicyScheme;828 R.MaskedPolicyScheme = SR.MaskedPolicyScheme;829 R.IsTuple = SR.IsTuple;830 R.HasFRMRoundModeOp = SR.HasFRMRoundModeOp;831 832 assert(R.PrototypeIndex !=833 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX));834 assert(R.SuffixIndex !=835 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX));836 assert(R.OverloadedSuffixIndex !=837 static_cast<uint16_t>(SemaSignatureTable::INVALID_INDEX));838 }839}840 841void RVVEmitter::createSema(raw_ostream &OS) {842 std::vector<std::unique_ptr<RVVIntrinsic>> Defs;843 std::vector<RVVIntrinsicRecord> RVVIntrinsicRecords;844 SemaSignatureTable SST;845 std::vector<SemaRecord> SemaRecords;846 847 createRVVIntrinsics(Defs, &SemaRecords);848 849 createRVVIntrinsicRecords(RVVIntrinsicRecords, SST, SemaRecords);850 851 // Emit signature table for SemaRISCVVectorLookup.cpp.852 OS << "#ifdef DECL_SIGNATURE_TABLE\n";853 SST.print(OS);854 OS << "#endif\n";855 856 // Emit RVVIntrinsicRecords for SemaRISCVVectorLookup.cpp.857 OS << "#ifdef DECL_INTRINSIC_RECORDS\n";858 for (const RVVIntrinsicRecord &Record : RVVIntrinsicRecords)859 OS << Record;860 OS << "#endif\n";861}862 863namespace clang {864void EmitRVVHeader(const RecordKeeper &Records, raw_ostream &OS) {865 RVVEmitter(Records).createHeader(OS);866}867 868void EmitRVVBuiltins(const RecordKeeper &Records, raw_ostream &OS) {869 RVVEmitter(Records).createBuiltins(OS);870}871 872void EmitRVVBuiltinCG(const RecordKeeper &Records, raw_ostream &OS) {873 RVVEmitter(Records).createCodeGen(OS);874}875 876void EmitRVVBuiltinSema(const RecordKeeper &Records, raw_ostream &OS) {877 RVVEmitter(Records).createSema(OS);878}879 880} // End namespace clang881