brintos

brintos / llvm-project-archived public Read only

0
0
Text · 32.0 KiB · c316dfd Raw
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