xref: /freebsd/contrib/llvm-project/clang/lib/Support/RISCVVIntrinsicUtils.cpp (revision 1ac55f4cb0001fed92329746c730aa9a947c09a5)
181ad6265SDimitry Andric //===- RISCVVIntrinsicUtils.cpp - RISC-V Vector Intrinsic Utils -*- C++ -*-===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric 
981ad6265SDimitry Andric #include "clang/Support/RISCVVIntrinsicUtils.h"
1081ad6265SDimitry Andric #include "llvm/ADT/ArrayRef.h"
1181ad6265SDimitry Andric #include "llvm/ADT/SmallSet.h"
1281ad6265SDimitry Andric #include "llvm/ADT/StringExtras.h"
1381ad6265SDimitry Andric #include "llvm/ADT/StringMap.h"
1481ad6265SDimitry Andric #include "llvm/ADT/StringSet.h"
1581ad6265SDimitry Andric #include "llvm/ADT/Twine.h"
16bdd1243dSDimitry Andric #include "llvm/Support/ErrorHandling.h"
1781ad6265SDimitry Andric #include "llvm/Support/raw_ostream.h"
1881ad6265SDimitry Andric #include <numeric>
19bdd1243dSDimitry Andric #include <optional>
2081ad6265SDimitry Andric 
2181ad6265SDimitry Andric using namespace llvm;
2281ad6265SDimitry Andric 
2381ad6265SDimitry Andric namespace clang {
2481ad6265SDimitry Andric namespace RISCV {
2581ad6265SDimitry Andric 
2681ad6265SDimitry Andric const PrototypeDescriptor PrototypeDescriptor::Mask = PrototypeDescriptor(
2781ad6265SDimitry Andric     BaseTypeModifier::Vector, VectorTypeModifier::MaskVector);
2881ad6265SDimitry Andric const PrototypeDescriptor PrototypeDescriptor::VL =
2981ad6265SDimitry Andric     PrototypeDescriptor(BaseTypeModifier::SizeT);
3081ad6265SDimitry Andric const PrototypeDescriptor PrototypeDescriptor::Vector =
3181ad6265SDimitry Andric     PrototypeDescriptor(BaseTypeModifier::Vector);
3281ad6265SDimitry Andric 
3381ad6265SDimitry Andric //===----------------------------------------------------------------------===//
3481ad6265SDimitry Andric // Type implementation
3581ad6265SDimitry Andric //===----------------------------------------------------------------------===//
3681ad6265SDimitry Andric 
3781ad6265SDimitry Andric LMULType::LMULType(int NewLog2LMUL) {
3881ad6265SDimitry Andric   // Check Log2LMUL is -3, -2, -1, 0, 1, 2, 3
3981ad6265SDimitry Andric   assert(NewLog2LMUL <= 3 && NewLog2LMUL >= -3 && "Bad LMUL number!");
4081ad6265SDimitry Andric   Log2LMUL = NewLog2LMUL;
4181ad6265SDimitry Andric }
4281ad6265SDimitry Andric 
4381ad6265SDimitry Andric std::string LMULType::str() const {
4481ad6265SDimitry Andric   if (Log2LMUL < 0)
4581ad6265SDimitry Andric     return "mf" + utostr(1ULL << (-Log2LMUL));
4681ad6265SDimitry Andric   return "m" + utostr(1ULL << Log2LMUL);
4781ad6265SDimitry Andric }
4881ad6265SDimitry Andric 
4981ad6265SDimitry Andric VScaleVal LMULType::getScale(unsigned ElementBitwidth) const {
5081ad6265SDimitry Andric   int Log2ScaleResult = 0;
5181ad6265SDimitry Andric   switch (ElementBitwidth) {
5281ad6265SDimitry Andric   default:
5381ad6265SDimitry Andric     break;
5481ad6265SDimitry Andric   case 8:
5581ad6265SDimitry Andric     Log2ScaleResult = Log2LMUL + 3;
5681ad6265SDimitry Andric     break;
5781ad6265SDimitry Andric   case 16:
5881ad6265SDimitry Andric     Log2ScaleResult = Log2LMUL + 2;
5981ad6265SDimitry Andric     break;
6081ad6265SDimitry Andric   case 32:
6181ad6265SDimitry Andric     Log2ScaleResult = Log2LMUL + 1;
6281ad6265SDimitry Andric     break;
6381ad6265SDimitry Andric   case 64:
6481ad6265SDimitry Andric     Log2ScaleResult = Log2LMUL;
6581ad6265SDimitry Andric     break;
6681ad6265SDimitry Andric   }
6781ad6265SDimitry Andric   // Illegal vscale result would be less than 1
6881ad6265SDimitry Andric   if (Log2ScaleResult < 0)
69bdd1243dSDimitry Andric     return std::nullopt;
7081ad6265SDimitry Andric   return 1 << Log2ScaleResult;
7181ad6265SDimitry Andric }
7281ad6265SDimitry Andric 
7381ad6265SDimitry Andric void LMULType::MulLog2LMUL(int log2LMUL) { Log2LMUL += log2LMUL; }
7481ad6265SDimitry Andric 
7581ad6265SDimitry Andric RVVType::RVVType(BasicType BT, int Log2LMUL,
7681ad6265SDimitry Andric                  const PrototypeDescriptor &prototype)
7781ad6265SDimitry Andric     : BT(BT), LMUL(LMULType(Log2LMUL)) {
7881ad6265SDimitry Andric   applyBasicType();
7981ad6265SDimitry Andric   applyModifier(prototype);
8081ad6265SDimitry Andric   Valid = verifyType();
8181ad6265SDimitry Andric   if (Valid) {
8281ad6265SDimitry Andric     initBuiltinStr();
8381ad6265SDimitry Andric     initTypeStr();
8481ad6265SDimitry Andric     if (isVector()) {
8581ad6265SDimitry Andric       initClangBuiltinStr();
8681ad6265SDimitry Andric     }
8781ad6265SDimitry Andric   }
8881ad6265SDimitry Andric }
8981ad6265SDimitry Andric 
9081ad6265SDimitry Andric // clang-format off
9181ad6265SDimitry Andric // boolean type are encoded the ratio of n (SEW/LMUL)
9281ad6265SDimitry Andric // SEW/LMUL | 1         | 2         | 4         | 8        | 16        | 32        | 64
9381ad6265SDimitry Andric // c type   | vbool64_t | vbool32_t | vbool16_t | vbool8_t | vbool4_t  | vbool2_t  | vbool1_t
9481ad6265SDimitry Andric // IR type  | nxv1i1    | nxv2i1    | nxv4i1    | nxv8i1   | nxv16i1   | nxv32i1   | nxv64i1
9581ad6265SDimitry Andric 
9681ad6265SDimitry Andric // type\lmul | 1/8    | 1/4      | 1/2     | 1       | 2        | 4        | 8
9781ad6265SDimitry Andric // --------  |------  | -------- | ------- | ------- | -------- | -------- | --------
9881ad6265SDimitry Andric // i64       | N/A    | N/A      | N/A     | nxv1i64 | nxv2i64  | nxv4i64  | nxv8i64
9981ad6265SDimitry Andric // i32       | N/A    | N/A      | nxv1i32 | nxv2i32 | nxv4i32  | nxv8i32  | nxv16i32
10081ad6265SDimitry Andric // i16       | N/A    | nxv1i16  | nxv2i16 | nxv4i16 | nxv8i16  | nxv16i16 | nxv32i16
10181ad6265SDimitry Andric // i8        | nxv1i8 | nxv2i8   | nxv4i8  | nxv8i8  | nxv16i8  | nxv32i8  | nxv64i8
10281ad6265SDimitry Andric // double    | N/A    | N/A      | N/A     | nxv1f64 | nxv2f64  | nxv4f64  | nxv8f64
10381ad6265SDimitry Andric // float     | N/A    | N/A      | nxv1f32 | nxv2f32 | nxv4f32  | nxv8f32  | nxv16f32
10481ad6265SDimitry Andric // half      | N/A    | nxv1f16  | nxv2f16 | nxv4f16 | nxv8f16  | nxv16f16 | nxv32f16
10581ad6265SDimitry Andric // clang-format on
10681ad6265SDimitry Andric 
10781ad6265SDimitry Andric bool RVVType::verifyType() const {
10881ad6265SDimitry Andric   if (ScalarType == Invalid)
10981ad6265SDimitry Andric     return false;
11081ad6265SDimitry Andric   if (isScalar())
11181ad6265SDimitry Andric     return true;
11281ad6265SDimitry Andric   if (!Scale)
11381ad6265SDimitry Andric     return false;
11481ad6265SDimitry Andric   if (isFloat() && ElementBitwidth == 8)
11581ad6265SDimitry Andric     return false;
116bdd1243dSDimitry Andric   unsigned V = *Scale;
11781ad6265SDimitry Andric   switch (ElementBitwidth) {
11881ad6265SDimitry Andric   case 1:
11981ad6265SDimitry Andric   case 8:
12081ad6265SDimitry Andric     // Check Scale is 1,2,4,8,16,32,64
12181ad6265SDimitry Andric     return (V <= 64 && isPowerOf2_32(V));
12281ad6265SDimitry Andric   case 16:
12381ad6265SDimitry Andric     // Check Scale is 1,2,4,8,16,32
12481ad6265SDimitry Andric     return (V <= 32 && isPowerOf2_32(V));
12581ad6265SDimitry Andric   case 32:
12681ad6265SDimitry Andric     // Check Scale is 1,2,4,8,16
12781ad6265SDimitry Andric     return (V <= 16 && isPowerOf2_32(V));
12881ad6265SDimitry Andric   case 64:
12981ad6265SDimitry Andric     // Check Scale is 1,2,4,8
13081ad6265SDimitry Andric     return (V <= 8 && isPowerOf2_32(V));
13181ad6265SDimitry Andric   }
13281ad6265SDimitry Andric   return false;
13381ad6265SDimitry Andric }
13481ad6265SDimitry Andric 
13581ad6265SDimitry Andric void RVVType::initBuiltinStr() {
13681ad6265SDimitry Andric   assert(isValid() && "RVVType is invalid");
13781ad6265SDimitry Andric   switch (ScalarType) {
13881ad6265SDimitry Andric   case ScalarTypeKind::Void:
13981ad6265SDimitry Andric     BuiltinStr = "v";
14081ad6265SDimitry Andric     return;
14181ad6265SDimitry Andric   case ScalarTypeKind::Size_t:
14281ad6265SDimitry Andric     BuiltinStr = "z";
14381ad6265SDimitry Andric     if (IsImmediate)
14481ad6265SDimitry Andric       BuiltinStr = "I" + BuiltinStr;
14581ad6265SDimitry Andric     if (IsPointer)
14681ad6265SDimitry Andric       BuiltinStr += "*";
14781ad6265SDimitry Andric     return;
14881ad6265SDimitry Andric   case ScalarTypeKind::Ptrdiff_t:
14981ad6265SDimitry Andric     BuiltinStr = "Y";
15081ad6265SDimitry Andric     return;
15181ad6265SDimitry Andric   case ScalarTypeKind::UnsignedLong:
15281ad6265SDimitry Andric     BuiltinStr = "ULi";
15381ad6265SDimitry Andric     return;
15481ad6265SDimitry Andric   case ScalarTypeKind::SignedLong:
15581ad6265SDimitry Andric     BuiltinStr = "Li";
15681ad6265SDimitry Andric     return;
15781ad6265SDimitry Andric   case ScalarTypeKind::Boolean:
15881ad6265SDimitry Andric     assert(ElementBitwidth == 1);
15981ad6265SDimitry Andric     BuiltinStr += "b";
16081ad6265SDimitry Andric     break;
16181ad6265SDimitry Andric   case ScalarTypeKind::SignedInteger:
16281ad6265SDimitry Andric   case ScalarTypeKind::UnsignedInteger:
16381ad6265SDimitry Andric     switch (ElementBitwidth) {
16481ad6265SDimitry Andric     case 8:
16581ad6265SDimitry Andric       BuiltinStr += "c";
16681ad6265SDimitry Andric       break;
16781ad6265SDimitry Andric     case 16:
16881ad6265SDimitry Andric       BuiltinStr += "s";
16981ad6265SDimitry Andric       break;
17081ad6265SDimitry Andric     case 32:
17181ad6265SDimitry Andric       BuiltinStr += "i";
17281ad6265SDimitry Andric       break;
17381ad6265SDimitry Andric     case 64:
17481ad6265SDimitry Andric       BuiltinStr += "Wi";
17581ad6265SDimitry Andric       break;
17681ad6265SDimitry Andric     default:
17781ad6265SDimitry Andric       llvm_unreachable("Unhandled ElementBitwidth!");
17881ad6265SDimitry Andric     }
17981ad6265SDimitry Andric     if (isSignedInteger())
18081ad6265SDimitry Andric       BuiltinStr = "S" + BuiltinStr;
18181ad6265SDimitry Andric     else
18281ad6265SDimitry Andric       BuiltinStr = "U" + BuiltinStr;
18381ad6265SDimitry Andric     break;
18481ad6265SDimitry Andric   case ScalarTypeKind::Float:
18581ad6265SDimitry Andric     switch (ElementBitwidth) {
18681ad6265SDimitry Andric     case 16:
18781ad6265SDimitry Andric       BuiltinStr += "x";
18881ad6265SDimitry Andric       break;
18981ad6265SDimitry Andric     case 32:
19081ad6265SDimitry Andric       BuiltinStr += "f";
19181ad6265SDimitry Andric       break;
19281ad6265SDimitry Andric     case 64:
19381ad6265SDimitry Andric       BuiltinStr += "d";
19481ad6265SDimitry Andric       break;
19581ad6265SDimitry Andric     default:
19681ad6265SDimitry Andric       llvm_unreachable("Unhandled ElementBitwidth!");
19781ad6265SDimitry Andric     }
19881ad6265SDimitry Andric     break;
19981ad6265SDimitry Andric   default:
20081ad6265SDimitry Andric     llvm_unreachable("ScalarType is invalid!");
20181ad6265SDimitry Andric   }
20281ad6265SDimitry Andric   if (IsImmediate)
20381ad6265SDimitry Andric     BuiltinStr = "I" + BuiltinStr;
20481ad6265SDimitry Andric   if (isScalar()) {
20581ad6265SDimitry Andric     if (IsConstant)
20681ad6265SDimitry Andric       BuiltinStr += "C";
20781ad6265SDimitry Andric     if (IsPointer)
20881ad6265SDimitry Andric       BuiltinStr += "*";
20981ad6265SDimitry Andric     return;
21081ad6265SDimitry Andric   }
21181ad6265SDimitry Andric   BuiltinStr = "q" + utostr(*Scale) + BuiltinStr;
21281ad6265SDimitry Andric   // Pointer to vector types. Defined for segment load intrinsics.
21381ad6265SDimitry Andric   // segment load intrinsics have pointer type arguments to store the loaded
21481ad6265SDimitry Andric   // vector values.
21581ad6265SDimitry Andric   if (IsPointer)
21681ad6265SDimitry Andric     BuiltinStr += "*";
21781ad6265SDimitry Andric }
21881ad6265SDimitry Andric 
21981ad6265SDimitry Andric void RVVType::initClangBuiltinStr() {
22081ad6265SDimitry Andric   assert(isValid() && "RVVType is invalid");
22181ad6265SDimitry Andric   assert(isVector() && "Handle Vector type only");
22281ad6265SDimitry Andric 
22381ad6265SDimitry Andric   ClangBuiltinStr = "__rvv_";
22481ad6265SDimitry Andric   switch (ScalarType) {
22581ad6265SDimitry Andric   case ScalarTypeKind::Boolean:
22681ad6265SDimitry Andric     ClangBuiltinStr += "bool" + utostr(64 / *Scale) + "_t";
22781ad6265SDimitry Andric     return;
22881ad6265SDimitry Andric   case ScalarTypeKind::Float:
22981ad6265SDimitry Andric     ClangBuiltinStr += "float";
23081ad6265SDimitry Andric     break;
23181ad6265SDimitry Andric   case ScalarTypeKind::SignedInteger:
23281ad6265SDimitry Andric     ClangBuiltinStr += "int";
23381ad6265SDimitry Andric     break;
23481ad6265SDimitry Andric   case ScalarTypeKind::UnsignedInteger:
23581ad6265SDimitry Andric     ClangBuiltinStr += "uint";
23681ad6265SDimitry Andric     break;
23781ad6265SDimitry Andric   default:
23881ad6265SDimitry Andric     llvm_unreachable("ScalarTypeKind is invalid");
23981ad6265SDimitry Andric   }
24081ad6265SDimitry Andric   ClangBuiltinStr += utostr(ElementBitwidth) + LMUL.str() + "_t";
24181ad6265SDimitry Andric }
24281ad6265SDimitry Andric 
24381ad6265SDimitry Andric void RVVType::initTypeStr() {
24481ad6265SDimitry Andric   assert(isValid() && "RVVType is invalid");
24581ad6265SDimitry Andric 
24681ad6265SDimitry Andric   if (IsConstant)
24781ad6265SDimitry Andric     Str += "const ";
24881ad6265SDimitry Andric 
24981ad6265SDimitry Andric   auto getTypeString = [&](StringRef TypeStr) {
25081ad6265SDimitry Andric     if (isScalar())
25181ad6265SDimitry Andric       return Twine(TypeStr + Twine(ElementBitwidth) + "_t").str();
25281ad6265SDimitry Andric     return Twine("v" + TypeStr + Twine(ElementBitwidth) + LMUL.str() + "_t")
25381ad6265SDimitry Andric         .str();
25481ad6265SDimitry Andric   };
25581ad6265SDimitry Andric 
25681ad6265SDimitry Andric   switch (ScalarType) {
25781ad6265SDimitry Andric   case ScalarTypeKind::Void:
25881ad6265SDimitry Andric     Str = "void";
25981ad6265SDimitry Andric     return;
26081ad6265SDimitry Andric   case ScalarTypeKind::Size_t:
26181ad6265SDimitry Andric     Str = "size_t";
26281ad6265SDimitry Andric     if (IsPointer)
26381ad6265SDimitry Andric       Str += " *";
26481ad6265SDimitry Andric     return;
26581ad6265SDimitry Andric   case ScalarTypeKind::Ptrdiff_t:
26681ad6265SDimitry Andric     Str = "ptrdiff_t";
26781ad6265SDimitry Andric     return;
26881ad6265SDimitry Andric   case ScalarTypeKind::UnsignedLong:
26981ad6265SDimitry Andric     Str = "unsigned long";
27081ad6265SDimitry Andric     return;
27181ad6265SDimitry Andric   case ScalarTypeKind::SignedLong:
27281ad6265SDimitry Andric     Str = "long";
27381ad6265SDimitry Andric     return;
27481ad6265SDimitry Andric   case ScalarTypeKind::Boolean:
27581ad6265SDimitry Andric     if (isScalar())
27681ad6265SDimitry Andric       Str += "bool";
27781ad6265SDimitry Andric     else
27881ad6265SDimitry Andric       // Vector bool is special case, the formulate is
27981ad6265SDimitry Andric       // `vbool<N>_t = MVT::nxv<64/N>i1` ex. vbool16_t = MVT::4i1
28081ad6265SDimitry Andric       Str += "vbool" + utostr(64 / *Scale) + "_t";
28181ad6265SDimitry Andric     break;
28281ad6265SDimitry Andric   case ScalarTypeKind::Float:
28381ad6265SDimitry Andric     if (isScalar()) {
28481ad6265SDimitry Andric       if (ElementBitwidth == 64)
28581ad6265SDimitry Andric         Str += "double";
28681ad6265SDimitry Andric       else if (ElementBitwidth == 32)
28781ad6265SDimitry Andric         Str += "float";
28881ad6265SDimitry Andric       else if (ElementBitwidth == 16)
28981ad6265SDimitry Andric         Str += "_Float16";
29081ad6265SDimitry Andric       else
29181ad6265SDimitry Andric         llvm_unreachable("Unhandled floating type.");
29281ad6265SDimitry Andric     } else
29381ad6265SDimitry Andric       Str += getTypeString("float");
29481ad6265SDimitry Andric     break;
29581ad6265SDimitry Andric   case ScalarTypeKind::SignedInteger:
29681ad6265SDimitry Andric     Str += getTypeString("int");
29781ad6265SDimitry Andric     break;
29881ad6265SDimitry Andric   case ScalarTypeKind::UnsignedInteger:
29981ad6265SDimitry Andric     Str += getTypeString("uint");
30081ad6265SDimitry Andric     break;
30181ad6265SDimitry Andric   default:
30281ad6265SDimitry Andric     llvm_unreachable("ScalarType is invalid!");
30381ad6265SDimitry Andric   }
30481ad6265SDimitry Andric   if (IsPointer)
30581ad6265SDimitry Andric     Str += " *";
30681ad6265SDimitry Andric }
30781ad6265SDimitry Andric 
30881ad6265SDimitry Andric void RVVType::initShortStr() {
30981ad6265SDimitry Andric   switch (ScalarType) {
31081ad6265SDimitry Andric   case ScalarTypeKind::Boolean:
31181ad6265SDimitry Andric     assert(isVector());
31281ad6265SDimitry Andric     ShortStr = "b" + utostr(64 / *Scale);
31381ad6265SDimitry Andric     return;
31481ad6265SDimitry Andric   case ScalarTypeKind::Float:
31581ad6265SDimitry Andric     ShortStr = "f" + utostr(ElementBitwidth);
31681ad6265SDimitry Andric     break;
31781ad6265SDimitry Andric   case ScalarTypeKind::SignedInteger:
31881ad6265SDimitry Andric     ShortStr = "i" + utostr(ElementBitwidth);
31981ad6265SDimitry Andric     break;
32081ad6265SDimitry Andric   case ScalarTypeKind::UnsignedInteger:
32181ad6265SDimitry Andric     ShortStr = "u" + utostr(ElementBitwidth);
32281ad6265SDimitry Andric     break;
32381ad6265SDimitry Andric   default:
32481ad6265SDimitry Andric     llvm_unreachable("Unhandled case!");
32581ad6265SDimitry Andric   }
32681ad6265SDimitry Andric   if (isVector())
32781ad6265SDimitry Andric     ShortStr += LMUL.str();
32881ad6265SDimitry Andric }
32981ad6265SDimitry Andric 
33081ad6265SDimitry Andric void RVVType::applyBasicType() {
33181ad6265SDimitry Andric   switch (BT) {
33281ad6265SDimitry Andric   case BasicType::Int8:
33381ad6265SDimitry Andric     ElementBitwidth = 8;
33481ad6265SDimitry Andric     ScalarType = ScalarTypeKind::SignedInteger;
33581ad6265SDimitry Andric     break;
33681ad6265SDimitry Andric   case BasicType::Int16:
33781ad6265SDimitry Andric     ElementBitwidth = 16;
33881ad6265SDimitry Andric     ScalarType = ScalarTypeKind::SignedInteger;
33981ad6265SDimitry Andric     break;
34081ad6265SDimitry Andric   case BasicType::Int32:
34181ad6265SDimitry Andric     ElementBitwidth = 32;
34281ad6265SDimitry Andric     ScalarType = ScalarTypeKind::SignedInteger;
34381ad6265SDimitry Andric     break;
34481ad6265SDimitry Andric   case BasicType::Int64:
34581ad6265SDimitry Andric     ElementBitwidth = 64;
34681ad6265SDimitry Andric     ScalarType = ScalarTypeKind::SignedInteger;
34781ad6265SDimitry Andric     break;
34881ad6265SDimitry Andric   case BasicType::Float16:
34981ad6265SDimitry Andric     ElementBitwidth = 16;
35081ad6265SDimitry Andric     ScalarType = ScalarTypeKind::Float;
35181ad6265SDimitry Andric     break;
35281ad6265SDimitry Andric   case BasicType::Float32:
35381ad6265SDimitry Andric     ElementBitwidth = 32;
35481ad6265SDimitry Andric     ScalarType = ScalarTypeKind::Float;
35581ad6265SDimitry Andric     break;
35681ad6265SDimitry Andric   case BasicType::Float64:
35781ad6265SDimitry Andric     ElementBitwidth = 64;
35881ad6265SDimitry Andric     ScalarType = ScalarTypeKind::Float;
35981ad6265SDimitry Andric     break;
36081ad6265SDimitry Andric   default:
36181ad6265SDimitry Andric     llvm_unreachable("Unhandled type code!");
36281ad6265SDimitry Andric   }
36381ad6265SDimitry Andric   assert(ElementBitwidth != 0 && "Bad element bitwidth!");
36481ad6265SDimitry Andric }
36581ad6265SDimitry Andric 
366bdd1243dSDimitry Andric std::optional<PrototypeDescriptor>
367bdd1243dSDimitry Andric PrototypeDescriptor::parsePrototypeDescriptor(
36881ad6265SDimitry Andric     llvm::StringRef PrototypeDescriptorStr) {
36981ad6265SDimitry Andric   PrototypeDescriptor PD;
37081ad6265SDimitry Andric   BaseTypeModifier PT = BaseTypeModifier::Invalid;
37181ad6265SDimitry Andric   VectorTypeModifier VTM = VectorTypeModifier::NoModifier;
37281ad6265SDimitry Andric 
37381ad6265SDimitry Andric   if (PrototypeDescriptorStr.empty())
37481ad6265SDimitry Andric     return PD;
37581ad6265SDimitry Andric 
37681ad6265SDimitry Andric   // Handle base type modifier
37781ad6265SDimitry Andric   auto PType = PrototypeDescriptorStr.back();
37881ad6265SDimitry Andric   switch (PType) {
37981ad6265SDimitry Andric   case 'e':
38081ad6265SDimitry Andric     PT = BaseTypeModifier::Scalar;
38181ad6265SDimitry Andric     break;
38281ad6265SDimitry Andric   case 'v':
38381ad6265SDimitry Andric     PT = BaseTypeModifier::Vector;
38481ad6265SDimitry Andric     break;
38581ad6265SDimitry Andric   case 'w':
38681ad6265SDimitry Andric     PT = BaseTypeModifier::Vector;
38781ad6265SDimitry Andric     VTM = VectorTypeModifier::Widening2XVector;
38881ad6265SDimitry Andric     break;
38981ad6265SDimitry Andric   case 'q':
39081ad6265SDimitry Andric     PT = BaseTypeModifier::Vector;
39181ad6265SDimitry Andric     VTM = VectorTypeModifier::Widening4XVector;
39281ad6265SDimitry Andric     break;
39381ad6265SDimitry Andric   case 'o':
39481ad6265SDimitry Andric     PT = BaseTypeModifier::Vector;
39581ad6265SDimitry Andric     VTM = VectorTypeModifier::Widening8XVector;
39681ad6265SDimitry Andric     break;
39781ad6265SDimitry Andric   case 'm':
39881ad6265SDimitry Andric     PT = BaseTypeModifier::Vector;
39981ad6265SDimitry Andric     VTM = VectorTypeModifier::MaskVector;
40081ad6265SDimitry Andric     break;
40181ad6265SDimitry Andric   case '0':
40281ad6265SDimitry Andric     PT = BaseTypeModifier::Void;
40381ad6265SDimitry Andric     break;
40481ad6265SDimitry Andric   case 'z':
40581ad6265SDimitry Andric     PT = BaseTypeModifier::SizeT;
40681ad6265SDimitry Andric     break;
40781ad6265SDimitry Andric   case 't':
40881ad6265SDimitry Andric     PT = BaseTypeModifier::Ptrdiff;
40981ad6265SDimitry Andric     break;
41081ad6265SDimitry Andric   case 'u':
41181ad6265SDimitry Andric     PT = BaseTypeModifier::UnsignedLong;
41281ad6265SDimitry Andric     break;
41381ad6265SDimitry Andric   case 'l':
41481ad6265SDimitry Andric     PT = BaseTypeModifier::SignedLong;
41581ad6265SDimitry Andric     break;
41681ad6265SDimitry Andric   default:
41781ad6265SDimitry Andric     llvm_unreachable("Illegal primitive type transformers!");
41881ad6265SDimitry Andric   }
41981ad6265SDimitry Andric   PD.PT = static_cast<uint8_t>(PT);
42081ad6265SDimitry Andric   PrototypeDescriptorStr = PrototypeDescriptorStr.drop_back();
42181ad6265SDimitry Andric 
42281ad6265SDimitry Andric   // Compute the vector type transformers, it can only appear one time.
42381ad6265SDimitry Andric   if (PrototypeDescriptorStr.startswith("(")) {
42481ad6265SDimitry Andric     assert(VTM == VectorTypeModifier::NoModifier &&
42581ad6265SDimitry Andric            "VectorTypeModifier should only have one modifier");
42681ad6265SDimitry Andric     size_t Idx = PrototypeDescriptorStr.find(')');
42781ad6265SDimitry Andric     assert(Idx != StringRef::npos);
42881ad6265SDimitry Andric     StringRef ComplexType = PrototypeDescriptorStr.slice(1, Idx);
42981ad6265SDimitry Andric     PrototypeDescriptorStr = PrototypeDescriptorStr.drop_front(Idx + 1);
43081ad6265SDimitry Andric     assert(!PrototypeDescriptorStr.contains('(') &&
43181ad6265SDimitry Andric            "Only allow one vector type modifier");
43281ad6265SDimitry Andric 
43381ad6265SDimitry Andric     auto ComplexTT = ComplexType.split(":");
43481ad6265SDimitry Andric     if (ComplexTT.first == "Log2EEW") {
43581ad6265SDimitry Andric       uint32_t Log2EEW;
43681ad6265SDimitry Andric       if (ComplexTT.second.getAsInteger(10, Log2EEW)) {
43781ad6265SDimitry Andric         llvm_unreachable("Invalid Log2EEW value!");
438bdd1243dSDimitry Andric         return std::nullopt;
43981ad6265SDimitry Andric       }
44081ad6265SDimitry Andric       switch (Log2EEW) {
44181ad6265SDimitry Andric       case 3:
44281ad6265SDimitry Andric         VTM = VectorTypeModifier::Log2EEW3;
44381ad6265SDimitry Andric         break;
44481ad6265SDimitry Andric       case 4:
44581ad6265SDimitry Andric         VTM = VectorTypeModifier::Log2EEW4;
44681ad6265SDimitry Andric         break;
44781ad6265SDimitry Andric       case 5:
44881ad6265SDimitry Andric         VTM = VectorTypeModifier::Log2EEW5;
44981ad6265SDimitry Andric         break;
45081ad6265SDimitry Andric       case 6:
45181ad6265SDimitry Andric         VTM = VectorTypeModifier::Log2EEW6;
45281ad6265SDimitry Andric         break;
45381ad6265SDimitry Andric       default:
45481ad6265SDimitry Andric         llvm_unreachable("Invalid Log2EEW value, should be [3-6]");
455bdd1243dSDimitry Andric         return std::nullopt;
45681ad6265SDimitry Andric       }
45781ad6265SDimitry Andric     } else if (ComplexTT.first == "FixedSEW") {
45881ad6265SDimitry Andric       uint32_t NewSEW;
45981ad6265SDimitry Andric       if (ComplexTT.second.getAsInteger(10, NewSEW)) {
46081ad6265SDimitry Andric         llvm_unreachable("Invalid FixedSEW value!");
461bdd1243dSDimitry Andric         return std::nullopt;
46281ad6265SDimitry Andric       }
46381ad6265SDimitry Andric       switch (NewSEW) {
46481ad6265SDimitry Andric       case 8:
46581ad6265SDimitry Andric         VTM = VectorTypeModifier::FixedSEW8;
46681ad6265SDimitry Andric         break;
46781ad6265SDimitry Andric       case 16:
46881ad6265SDimitry Andric         VTM = VectorTypeModifier::FixedSEW16;
46981ad6265SDimitry Andric         break;
47081ad6265SDimitry Andric       case 32:
47181ad6265SDimitry Andric         VTM = VectorTypeModifier::FixedSEW32;
47281ad6265SDimitry Andric         break;
47381ad6265SDimitry Andric       case 64:
47481ad6265SDimitry Andric         VTM = VectorTypeModifier::FixedSEW64;
47581ad6265SDimitry Andric         break;
47681ad6265SDimitry Andric       default:
47781ad6265SDimitry Andric         llvm_unreachable("Invalid FixedSEW value, should be 8, 16, 32 or 64");
478bdd1243dSDimitry Andric         return std::nullopt;
47981ad6265SDimitry Andric       }
48081ad6265SDimitry Andric     } else if (ComplexTT.first == "LFixedLog2LMUL") {
48181ad6265SDimitry Andric       int32_t Log2LMUL;
48281ad6265SDimitry Andric       if (ComplexTT.second.getAsInteger(10, Log2LMUL)) {
48381ad6265SDimitry Andric         llvm_unreachable("Invalid LFixedLog2LMUL value!");
484bdd1243dSDimitry Andric         return std::nullopt;
48581ad6265SDimitry Andric       }
48681ad6265SDimitry Andric       switch (Log2LMUL) {
48781ad6265SDimitry Andric       case -3:
48881ad6265SDimitry Andric         VTM = VectorTypeModifier::LFixedLog2LMULN3;
48981ad6265SDimitry Andric         break;
49081ad6265SDimitry Andric       case -2:
49181ad6265SDimitry Andric         VTM = VectorTypeModifier::LFixedLog2LMULN2;
49281ad6265SDimitry Andric         break;
49381ad6265SDimitry Andric       case -1:
49481ad6265SDimitry Andric         VTM = VectorTypeModifier::LFixedLog2LMULN1;
49581ad6265SDimitry Andric         break;
49681ad6265SDimitry Andric       case 0:
49781ad6265SDimitry Andric         VTM = VectorTypeModifier::LFixedLog2LMUL0;
49881ad6265SDimitry Andric         break;
49981ad6265SDimitry Andric       case 1:
50081ad6265SDimitry Andric         VTM = VectorTypeModifier::LFixedLog2LMUL1;
50181ad6265SDimitry Andric         break;
50281ad6265SDimitry Andric       case 2:
50381ad6265SDimitry Andric         VTM = VectorTypeModifier::LFixedLog2LMUL2;
50481ad6265SDimitry Andric         break;
50581ad6265SDimitry Andric       case 3:
50681ad6265SDimitry Andric         VTM = VectorTypeModifier::LFixedLog2LMUL3;
50781ad6265SDimitry Andric         break;
50881ad6265SDimitry Andric       default:
50981ad6265SDimitry Andric         llvm_unreachable("Invalid LFixedLog2LMUL value, should be [-3, 3]");
510bdd1243dSDimitry Andric         return std::nullopt;
51181ad6265SDimitry Andric       }
51281ad6265SDimitry Andric     } else if (ComplexTT.first == "SFixedLog2LMUL") {
51381ad6265SDimitry Andric       int32_t Log2LMUL;
51481ad6265SDimitry Andric       if (ComplexTT.second.getAsInteger(10, Log2LMUL)) {
51581ad6265SDimitry Andric         llvm_unreachable("Invalid SFixedLog2LMUL value!");
516bdd1243dSDimitry Andric         return std::nullopt;
51781ad6265SDimitry Andric       }
51881ad6265SDimitry Andric       switch (Log2LMUL) {
51981ad6265SDimitry Andric       case -3:
52081ad6265SDimitry Andric         VTM = VectorTypeModifier::SFixedLog2LMULN3;
52181ad6265SDimitry Andric         break;
52281ad6265SDimitry Andric       case -2:
52381ad6265SDimitry Andric         VTM = VectorTypeModifier::SFixedLog2LMULN2;
52481ad6265SDimitry Andric         break;
52581ad6265SDimitry Andric       case -1:
52681ad6265SDimitry Andric         VTM = VectorTypeModifier::SFixedLog2LMULN1;
52781ad6265SDimitry Andric         break;
52881ad6265SDimitry Andric       case 0:
52981ad6265SDimitry Andric         VTM = VectorTypeModifier::SFixedLog2LMUL0;
53081ad6265SDimitry Andric         break;
53181ad6265SDimitry Andric       case 1:
53281ad6265SDimitry Andric         VTM = VectorTypeModifier::SFixedLog2LMUL1;
53381ad6265SDimitry Andric         break;
53481ad6265SDimitry Andric       case 2:
53581ad6265SDimitry Andric         VTM = VectorTypeModifier::SFixedLog2LMUL2;
53681ad6265SDimitry Andric         break;
53781ad6265SDimitry Andric       case 3:
53881ad6265SDimitry Andric         VTM = VectorTypeModifier::SFixedLog2LMUL3;
53981ad6265SDimitry Andric         break;
54081ad6265SDimitry Andric       default:
54181ad6265SDimitry Andric         llvm_unreachable("Invalid LFixedLog2LMUL value, should be [-3, 3]");
542bdd1243dSDimitry Andric         return std::nullopt;
54381ad6265SDimitry Andric       }
54481ad6265SDimitry Andric 
54581ad6265SDimitry Andric     } else {
54681ad6265SDimitry Andric       llvm_unreachable("Illegal complex type transformers!");
54781ad6265SDimitry Andric     }
54881ad6265SDimitry Andric   }
54981ad6265SDimitry Andric   PD.VTM = static_cast<uint8_t>(VTM);
55081ad6265SDimitry Andric 
55181ad6265SDimitry Andric   // Compute the remain type transformers
55281ad6265SDimitry Andric   TypeModifier TM = TypeModifier::NoModifier;
55381ad6265SDimitry Andric   for (char I : PrototypeDescriptorStr) {
55481ad6265SDimitry Andric     switch (I) {
55581ad6265SDimitry Andric     case 'P':
55681ad6265SDimitry Andric       if ((TM & TypeModifier::Const) == TypeModifier::Const)
55781ad6265SDimitry Andric         llvm_unreachable("'P' transformer cannot be used after 'C'");
55881ad6265SDimitry Andric       if ((TM & TypeModifier::Pointer) == TypeModifier::Pointer)
55981ad6265SDimitry Andric         llvm_unreachable("'P' transformer cannot be used twice");
56081ad6265SDimitry Andric       TM |= TypeModifier::Pointer;
56181ad6265SDimitry Andric       break;
56281ad6265SDimitry Andric     case 'C':
56381ad6265SDimitry Andric       TM |= TypeModifier::Const;
56481ad6265SDimitry Andric       break;
56581ad6265SDimitry Andric     case 'K':
56681ad6265SDimitry Andric       TM |= TypeModifier::Immediate;
56781ad6265SDimitry Andric       break;
56881ad6265SDimitry Andric     case 'U':
56981ad6265SDimitry Andric       TM |= TypeModifier::UnsignedInteger;
57081ad6265SDimitry Andric       break;
57181ad6265SDimitry Andric     case 'I':
57281ad6265SDimitry Andric       TM |= TypeModifier::SignedInteger;
57381ad6265SDimitry Andric       break;
57481ad6265SDimitry Andric     case 'F':
57581ad6265SDimitry Andric       TM |= TypeModifier::Float;
57681ad6265SDimitry Andric       break;
57781ad6265SDimitry Andric     case 'S':
57881ad6265SDimitry Andric       TM |= TypeModifier::LMUL1;
57981ad6265SDimitry Andric       break;
58081ad6265SDimitry Andric     default:
58181ad6265SDimitry Andric       llvm_unreachable("Illegal non-primitive type transformer!");
58281ad6265SDimitry Andric     }
58381ad6265SDimitry Andric   }
58481ad6265SDimitry Andric   PD.TM = static_cast<uint8_t>(TM);
58581ad6265SDimitry Andric 
58681ad6265SDimitry Andric   return PD;
58781ad6265SDimitry Andric }
58881ad6265SDimitry Andric 
58981ad6265SDimitry Andric void RVVType::applyModifier(const PrototypeDescriptor &Transformer) {
59081ad6265SDimitry Andric   // Handle primitive type transformer
59181ad6265SDimitry Andric   switch (static_cast<BaseTypeModifier>(Transformer.PT)) {
59281ad6265SDimitry Andric   case BaseTypeModifier::Scalar:
59381ad6265SDimitry Andric     Scale = 0;
59481ad6265SDimitry Andric     break;
59581ad6265SDimitry Andric   case BaseTypeModifier::Vector:
59681ad6265SDimitry Andric     Scale = LMUL.getScale(ElementBitwidth);
59781ad6265SDimitry Andric     break;
59881ad6265SDimitry Andric   case BaseTypeModifier::Void:
59981ad6265SDimitry Andric     ScalarType = ScalarTypeKind::Void;
60081ad6265SDimitry Andric     break;
60181ad6265SDimitry Andric   case BaseTypeModifier::SizeT:
60281ad6265SDimitry Andric     ScalarType = ScalarTypeKind::Size_t;
60381ad6265SDimitry Andric     break;
60481ad6265SDimitry Andric   case BaseTypeModifier::Ptrdiff:
60581ad6265SDimitry Andric     ScalarType = ScalarTypeKind::Ptrdiff_t;
60681ad6265SDimitry Andric     break;
60781ad6265SDimitry Andric   case BaseTypeModifier::UnsignedLong:
60881ad6265SDimitry Andric     ScalarType = ScalarTypeKind::UnsignedLong;
60981ad6265SDimitry Andric     break;
61081ad6265SDimitry Andric   case BaseTypeModifier::SignedLong:
61181ad6265SDimitry Andric     ScalarType = ScalarTypeKind::SignedLong;
61281ad6265SDimitry Andric     break;
61381ad6265SDimitry Andric   case BaseTypeModifier::Invalid:
61481ad6265SDimitry Andric     ScalarType = ScalarTypeKind::Invalid;
61581ad6265SDimitry Andric     return;
61681ad6265SDimitry Andric   }
61781ad6265SDimitry Andric 
61881ad6265SDimitry Andric   switch (static_cast<VectorTypeModifier>(Transformer.VTM)) {
61981ad6265SDimitry Andric   case VectorTypeModifier::Widening2XVector:
62081ad6265SDimitry Andric     ElementBitwidth *= 2;
62181ad6265SDimitry Andric     LMUL.MulLog2LMUL(1);
62281ad6265SDimitry Andric     Scale = LMUL.getScale(ElementBitwidth);
62381ad6265SDimitry Andric     break;
62481ad6265SDimitry Andric   case VectorTypeModifier::Widening4XVector:
62581ad6265SDimitry Andric     ElementBitwidth *= 4;
62681ad6265SDimitry Andric     LMUL.MulLog2LMUL(2);
62781ad6265SDimitry Andric     Scale = LMUL.getScale(ElementBitwidth);
62881ad6265SDimitry Andric     break;
62981ad6265SDimitry Andric   case VectorTypeModifier::Widening8XVector:
63081ad6265SDimitry Andric     ElementBitwidth *= 8;
63181ad6265SDimitry Andric     LMUL.MulLog2LMUL(3);
63281ad6265SDimitry Andric     Scale = LMUL.getScale(ElementBitwidth);
63381ad6265SDimitry Andric     break;
63481ad6265SDimitry Andric   case VectorTypeModifier::MaskVector:
63581ad6265SDimitry Andric     ScalarType = ScalarTypeKind::Boolean;
63681ad6265SDimitry Andric     Scale = LMUL.getScale(ElementBitwidth);
63781ad6265SDimitry Andric     ElementBitwidth = 1;
63881ad6265SDimitry Andric     break;
63981ad6265SDimitry Andric   case VectorTypeModifier::Log2EEW3:
64081ad6265SDimitry Andric     applyLog2EEW(3);
64181ad6265SDimitry Andric     break;
64281ad6265SDimitry Andric   case VectorTypeModifier::Log2EEW4:
64381ad6265SDimitry Andric     applyLog2EEW(4);
64481ad6265SDimitry Andric     break;
64581ad6265SDimitry Andric   case VectorTypeModifier::Log2EEW5:
64681ad6265SDimitry Andric     applyLog2EEW(5);
64781ad6265SDimitry Andric     break;
64881ad6265SDimitry Andric   case VectorTypeModifier::Log2EEW6:
64981ad6265SDimitry Andric     applyLog2EEW(6);
65081ad6265SDimitry Andric     break;
65181ad6265SDimitry Andric   case VectorTypeModifier::FixedSEW8:
65281ad6265SDimitry Andric     applyFixedSEW(8);
65381ad6265SDimitry Andric     break;
65481ad6265SDimitry Andric   case VectorTypeModifier::FixedSEW16:
65581ad6265SDimitry Andric     applyFixedSEW(16);
65681ad6265SDimitry Andric     break;
65781ad6265SDimitry Andric   case VectorTypeModifier::FixedSEW32:
65881ad6265SDimitry Andric     applyFixedSEW(32);
65981ad6265SDimitry Andric     break;
66081ad6265SDimitry Andric   case VectorTypeModifier::FixedSEW64:
66181ad6265SDimitry Andric     applyFixedSEW(64);
66281ad6265SDimitry Andric     break;
66381ad6265SDimitry Andric   case VectorTypeModifier::LFixedLog2LMULN3:
66481ad6265SDimitry Andric     applyFixedLog2LMUL(-3, FixedLMULType::LargerThan);
66581ad6265SDimitry Andric     break;
66681ad6265SDimitry Andric   case VectorTypeModifier::LFixedLog2LMULN2:
66781ad6265SDimitry Andric     applyFixedLog2LMUL(-2, FixedLMULType::LargerThan);
66881ad6265SDimitry Andric     break;
66981ad6265SDimitry Andric   case VectorTypeModifier::LFixedLog2LMULN1:
67081ad6265SDimitry Andric     applyFixedLog2LMUL(-1, FixedLMULType::LargerThan);
67181ad6265SDimitry Andric     break;
67281ad6265SDimitry Andric   case VectorTypeModifier::LFixedLog2LMUL0:
67381ad6265SDimitry Andric     applyFixedLog2LMUL(0, FixedLMULType::LargerThan);
67481ad6265SDimitry Andric     break;
67581ad6265SDimitry Andric   case VectorTypeModifier::LFixedLog2LMUL1:
67681ad6265SDimitry Andric     applyFixedLog2LMUL(1, FixedLMULType::LargerThan);
67781ad6265SDimitry Andric     break;
67881ad6265SDimitry Andric   case VectorTypeModifier::LFixedLog2LMUL2:
67981ad6265SDimitry Andric     applyFixedLog2LMUL(2, FixedLMULType::LargerThan);
68081ad6265SDimitry Andric     break;
68181ad6265SDimitry Andric   case VectorTypeModifier::LFixedLog2LMUL3:
68281ad6265SDimitry Andric     applyFixedLog2LMUL(3, FixedLMULType::LargerThan);
68381ad6265SDimitry Andric     break;
68481ad6265SDimitry Andric   case VectorTypeModifier::SFixedLog2LMULN3:
68581ad6265SDimitry Andric     applyFixedLog2LMUL(-3, FixedLMULType::SmallerThan);
68681ad6265SDimitry Andric     break;
68781ad6265SDimitry Andric   case VectorTypeModifier::SFixedLog2LMULN2:
68881ad6265SDimitry Andric     applyFixedLog2LMUL(-2, FixedLMULType::SmallerThan);
68981ad6265SDimitry Andric     break;
69081ad6265SDimitry Andric   case VectorTypeModifier::SFixedLog2LMULN1:
69181ad6265SDimitry Andric     applyFixedLog2LMUL(-1, FixedLMULType::SmallerThan);
69281ad6265SDimitry Andric     break;
69381ad6265SDimitry Andric   case VectorTypeModifier::SFixedLog2LMUL0:
69481ad6265SDimitry Andric     applyFixedLog2LMUL(0, FixedLMULType::SmallerThan);
69581ad6265SDimitry Andric     break;
69681ad6265SDimitry Andric   case VectorTypeModifier::SFixedLog2LMUL1:
69781ad6265SDimitry Andric     applyFixedLog2LMUL(1, FixedLMULType::SmallerThan);
69881ad6265SDimitry Andric     break;
69981ad6265SDimitry Andric   case VectorTypeModifier::SFixedLog2LMUL2:
70081ad6265SDimitry Andric     applyFixedLog2LMUL(2, FixedLMULType::SmallerThan);
70181ad6265SDimitry Andric     break;
70281ad6265SDimitry Andric   case VectorTypeModifier::SFixedLog2LMUL3:
70381ad6265SDimitry Andric     applyFixedLog2LMUL(3, FixedLMULType::SmallerThan);
70481ad6265SDimitry Andric     break;
70581ad6265SDimitry Andric   case VectorTypeModifier::NoModifier:
70681ad6265SDimitry Andric     break;
70781ad6265SDimitry Andric   }
70881ad6265SDimitry Andric 
70981ad6265SDimitry Andric   for (unsigned TypeModifierMaskShift = 0;
71081ad6265SDimitry Andric        TypeModifierMaskShift <= static_cast<unsigned>(TypeModifier::MaxOffset);
71181ad6265SDimitry Andric        ++TypeModifierMaskShift) {
71281ad6265SDimitry Andric     unsigned TypeModifierMask = 1 << TypeModifierMaskShift;
71381ad6265SDimitry Andric     if ((static_cast<unsigned>(Transformer.TM) & TypeModifierMask) !=
71481ad6265SDimitry Andric         TypeModifierMask)
71581ad6265SDimitry Andric       continue;
71681ad6265SDimitry Andric     switch (static_cast<TypeModifier>(TypeModifierMask)) {
71781ad6265SDimitry Andric     case TypeModifier::Pointer:
71881ad6265SDimitry Andric       IsPointer = true;
71981ad6265SDimitry Andric       break;
72081ad6265SDimitry Andric     case TypeModifier::Const:
72181ad6265SDimitry Andric       IsConstant = true;
72281ad6265SDimitry Andric       break;
72381ad6265SDimitry Andric     case TypeModifier::Immediate:
72481ad6265SDimitry Andric       IsImmediate = true;
72581ad6265SDimitry Andric       IsConstant = true;
72681ad6265SDimitry Andric       break;
72781ad6265SDimitry Andric     case TypeModifier::UnsignedInteger:
72881ad6265SDimitry Andric       ScalarType = ScalarTypeKind::UnsignedInteger;
72981ad6265SDimitry Andric       break;
73081ad6265SDimitry Andric     case TypeModifier::SignedInteger:
73181ad6265SDimitry Andric       ScalarType = ScalarTypeKind::SignedInteger;
73281ad6265SDimitry Andric       break;
73381ad6265SDimitry Andric     case TypeModifier::Float:
73481ad6265SDimitry Andric       ScalarType = ScalarTypeKind::Float;
73581ad6265SDimitry Andric       break;
73681ad6265SDimitry Andric     case TypeModifier::LMUL1:
73781ad6265SDimitry Andric       LMUL = LMULType(0);
73881ad6265SDimitry Andric       // Update ElementBitwidth need to update Scale too.
73981ad6265SDimitry Andric       Scale = LMUL.getScale(ElementBitwidth);
74081ad6265SDimitry Andric       break;
74181ad6265SDimitry Andric     default:
74281ad6265SDimitry Andric       llvm_unreachable("Unknown type modifier mask!");
74381ad6265SDimitry Andric     }
74481ad6265SDimitry Andric   }
74581ad6265SDimitry Andric }
74681ad6265SDimitry Andric 
74781ad6265SDimitry Andric void RVVType::applyLog2EEW(unsigned Log2EEW) {
74881ad6265SDimitry Andric   // update new elmul = (eew/sew) * lmul
74981ad6265SDimitry Andric   LMUL.MulLog2LMUL(Log2EEW - Log2_32(ElementBitwidth));
75081ad6265SDimitry Andric   // update new eew
75181ad6265SDimitry Andric   ElementBitwidth = 1 << Log2EEW;
75281ad6265SDimitry Andric   ScalarType = ScalarTypeKind::SignedInteger;
75381ad6265SDimitry Andric   Scale = LMUL.getScale(ElementBitwidth);
75481ad6265SDimitry Andric }
75581ad6265SDimitry Andric 
75681ad6265SDimitry Andric void RVVType::applyFixedSEW(unsigned NewSEW) {
75781ad6265SDimitry Andric   // Set invalid type if src and dst SEW are same.
75881ad6265SDimitry Andric   if (ElementBitwidth == NewSEW) {
75981ad6265SDimitry Andric     ScalarType = ScalarTypeKind::Invalid;
76081ad6265SDimitry Andric     return;
76181ad6265SDimitry Andric   }
76281ad6265SDimitry Andric   // Update new SEW
76381ad6265SDimitry Andric   ElementBitwidth = NewSEW;
76481ad6265SDimitry Andric   Scale = LMUL.getScale(ElementBitwidth);
76581ad6265SDimitry Andric }
76681ad6265SDimitry Andric 
76781ad6265SDimitry Andric void RVVType::applyFixedLog2LMUL(int Log2LMUL, enum FixedLMULType Type) {
76881ad6265SDimitry Andric   switch (Type) {
76981ad6265SDimitry Andric   case FixedLMULType::LargerThan:
77081ad6265SDimitry Andric     if (Log2LMUL < LMUL.Log2LMUL) {
77181ad6265SDimitry Andric       ScalarType = ScalarTypeKind::Invalid;
77281ad6265SDimitry Andric       return;
77381ad6265SDimitry Andric     }
77481ad6265SDimitry Andric     break;
77581ad6265SDimitry Andric   case FixedLMULType::SmallerThan:
77681ad6265SDimitry Andric     if (Log2LMUL > LMUL.Log2LMUL) {
77781ad6265SDimitry Andric       ScalarType = ScalarTypeKind::Invalid;
77881ad6265SDimitry Andric       return;
77981ad6265SDimitry Andric     }
78081ad6265SDimitry Andric     break;
78181ad6265SDimitry Andric   }
78281ad6265SDimitry Andric 
78381ad6265SDimitry Andric   // Update new LMUL
78481ad6265SDimitry Andric   LMUL = LMULType(Log2LMUL);
78581ad6265SDimitry Andric   Scale = LMUL.getScale(ElementBitwidth);
78681ad6265SDimitry Andric }
78781ad6265SDimitry Andric 
788bdd1243dSDimitry Andric std::optional<RVVTypes>
789bdd1243dSDimitry Andric RVVTypeCache::computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
79081ad6265SDimitry Andric                            ArrayRef<PrototypeDescriptor> Prototype) {
79181ad6265SDimitry Andric   // LMUL x NF must be less than or equal to 8.
79281ad6265SDimitry Andric   if ((Log2LMUL >= 1) && (1 << Log2LMUL) * NF > 8)
793bdd1243dSDimitry Andric     return std::nullopt;
79481ad6265SDimitry Andric 
79581ad6265SDimitry Andric   RVVTypes Types;
79681ad6265SDimitry Andric   for (const PrototypeDescriptor &Proto : Prototype) {
79781ad6265SDimitry Andric     auto T = computeType(BT, Log2LMUL, Proto);
79881ad6265SDimitry Andric     if (!T)
799bdd1243dSDimitry Andric       return std::nullopt;
80081ad6265SDimitry Andric     // Record legal type index
801bdd1243dSDimitry Andric     Types.push_back(*T);
80281ad6265SDimitry Andric   }
80381ad6265SDimitry Andric   return Types;
80481ad6265SDimitry Andric }
80581ad6265SDimitry Andric 
80681ad6265SDimitry Andric // Compute the hash value of RVVType, used for cache the result of computeType.
80781ad6265SDimitry Andric static uint64_t computeRVVTypeHashValue(BasicType BT, int Log2LMUL,
80881ad6265SDimitry Andric                                         PrototypeDescriptor Proto) {
80981ad6265SDimitry Andric   // Layout of hash value:
81081ad6265SDimitry Andric   // 0               8    16          24        32          40
81181ad6265SDimitry Andric   // | Log2LMUL + 3  | BT  | Proto.PT | Proto.TM | Proto.VTM |
81281ad6265SDimitry Andric   assert(Log2LMUL >= -3 && Log2LMUL <= 3);
81381ad6265SDimitry Andric   return (Log2LMUL + 3) | (static_cast<uint64_t>(BT) & 0xff) << 8 |
81481ad6265SDimitry Andric          ((uint64_t)(Proto.PT & 0xff) << 16) |
81581ad6265SDimitry Andric          ((uint64_t)(Proto.TM & 0xff) << 24) |
81681ad6265SDimitry Andric          ((uint64_t)(Proto.VTM & 0xff) << 32);
81781ad6265SDimitry Andric }
81881ad6265SDimitry Andric 
819bdd1243dSDimitry Andric std::optional<RVVTypePtr> RVVTypeCache::computeType(BasicType BT, int Log2LMUL,
82081ad6265SDimitry Andric                                                     PrototypeDescriptor Proto) {
82181ad6265SDimitry Andric   uint64_t Idx = computeRVVTypeHashValue(BT, Log2LMUL, Proto);
82281ad6265SDimitry Andric   // Search first
82381ad6265SDimitry Andric   auto It = LegalTypes.find(Idx);
82481ad6265SDimitry Andric   if (It != LegalTypes.end())
82581ad6265SDimitry Andric     return &(It->second);
82681ad6265SDimitry Andric 
82781ad6265SDimitry Andric   if (IllegalTypes.count(Idx))
828bdd1243dSDimitry Andric     return std::nullopt;
82981ad6265SDimitry Andric 
83081ad6265SDimitry Andric   // Compute type and record the result.
83181ad6265SDimitry Andric   RVVType T(BT, Log2LMUL, Proto);
83281ad6265SDimitry Andric   if (T.isValid()) {
83381ad6265SDimitry Andric     // Record legal type index and value.
834bdd1243dSDimitry Andric     std::pair<std::unordered_map<uint64_t, RVVType>::iterator, bool>
835bdd1243dSDimitry Andric         InsertResult = LegalTypes.insert({Idx, T});
836bdd1243dSDimitry Andric     return &(InsertResult.first->second);
83781ad6265SDimitry Andric   }
83881ad6265SDimitry Andric   // Record illegal type index.
83981ad6265SDimitry Andric   IllegalTypes.insert(Idx);
840bdd1243dSDimitry Andric   return std::nullopt;
84181ad6265SDimitry Andric }
84281ad6265SDimitry Andric 
84381ad6265SDimitry Andric //===----------------------------------------------------------------------===//
84481ad6265SDimitry Andric // RVVIntrinsic implementation
84581ad6265SDimitry Andric //===----------------------------------------------------------------------===//
846bdd1243dSDimitry Andric RVVIntrinsic::RVVIntrinsic(StringRef NewName, StringRef Suffix,
847bdd1243dSDimitry Andric                            StringRef NewOverloadedName,
848bdd1243dSDimitry Andric                            StringRef OverloadedSuffix, StringRef IRName,
849bdd1243dSDimitry Andric                            bool IsMasked, bool HasMaskedOffOperand, bool HasVL,
850bdd1243dSDimitry Andric                            PolicyScheme Scheme, bool SupportOverloading,
851bdd1243dSDimitry Andric                            bool HasBuiltinAlias, StringRef ManualCodegen,
852bdd1243dSDimitry Andric                            const RVVTypes &OutInTypes,
853bdd1243dSDimitry Andric                            const std::vector<int64_t> &NewIntrinsicTypes,
854bdd1243dSDimitry Andric                            const std::vector<StringRef> &RequiredFeatures,
855bdd1243dSDimitry Andric                            unsigned NF, Policy NewPolicyAttrs)
856bdd1243dSDimitry Andric     : IRName(IRName), IsMasked(IsMasked),
857bdd1243dSDimitry Andric       HasMaskedOffOperand(HasMaskedOffOperand), HasVL(HasVL), Scheme(Scheme),
858bdd1243dSDimitry Andric       SupportOverloading(SupportOverloading), HasBuiltinAlias(HasBuiltinAlias),
859bdd1243dSDimitry Andric       ManualCodegen(ManualCodegen.str()), NF(NF), PolicyAttrs(NewPolicyAttrs) {
86081ad6265SDimitry Andric 
86181ad6265SDimitry Andric   // Init BuiltinName, Name and OverloadedName
86281ad6265SDimitry Andric   BuiltinName = NewName.str();
86381ad6265SDimitry Andric   Name = BuiltinName;
86481ad6265SDimitry Andric   if (NewOverloadedName.empty())
86581ad6265SDimitry Andric     OverloadedName = NewName.split("_").first.str();
86681ad6265SDimitry Andric   else
86781ad6265SDimitry Andric     OverloadedName = NewOverloadedName.str();
86881ad6265SDimitry Andric   if (!Suffix.empty())
86981ad6265SDimitry Andric     Name += "_" + Suffix.str();
87081ad6265SDimitry Andric   if (!OverloadedSuffix.empty())
87181ad6265SDimitry Andric     OverloadedName += "_" + OverloadedSuffix.str();
872bdd1243dSDimitry Andric 
873bdd1243dSDimitry Andric   updateNamesAndPolicy(IsMasked, hasPolicy(), Name, BuiltinName, OverloadedName,
874bdd1243dSDimitry Andric                        PolicyAttrs);
87581ad6265SDimitry Andric 
87681ad6265SDimitry Andric   // Init OutputType and InputTypes
87781ad6265SDimitry Andric   OutputType = OutInTypes[0];
87881ad6265SDimitry Andric   InputTypes.assign(OutInTypes.begin() + 1, OutInTypes.end());
87981ad6265SDimitry Andric 
88081ad6265SDimitry Andric   // IntrinsicTypes is unmasked TA version index. Need to update it
88181ad6265SDimitry Andric   // if there is merge operand (It is always in first operand).
88281ad6265SDimitry Andric   IntrinsicTypes = NewIntrinsicTypes;
883bdd1243dSDimitry Andric   if ((IsMasked && hasMaskedOffOperand()) ||
88481ad6265SDimitry Andric       (!IsMasked && hasPassthruOperand())) {
88581ad6265SDimitry Andric     for (auto &I : IntrinsicTypes) {
88681ad6265SDimitry Andric       if (I >= 0)
88781ad6265SDimitry Andric         I += NF;
88881ad6265SDimitry Andric     }
88981ad6265SDimitry Andric   }
89081ad6265SDimitry Andric }
89181ad6265SDimitry Andric 
89281ad6265SDimitry Andric std::string RVVIntrinsic::getBuiltinTypeStr() const {
89381ad6265SDimitry Andric   std::string S;
89481ad6265SDimitry Andric   S += OutputType->getBuiltinStr();
89581ad6265SDimitry Andric   for (const auto &T : InputTypes) {
89681ad6265SDimitry Andric     S += T->getBuiltinStr();
89781ad6265SDimitry Andric   }
89881ad6265SDimitry Andric   return S;
89981ad6265SDimitry Andric }
90081ad6265SDimitry Andric 
90181ad6265SDimitry Andric std::string RVVIntrinsic::getSuffixStr(
902bdd1243dSDimitry Andric     RVVTypeCache &TypeCache, BasicType Type, int Log2LMUL,
90381ad6265SDimitry Andric     llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors) {
90481ad6265SDimitry Andric   SmallVector<std::string> SuffixStrs;
90581ad6265SDimitry Andric   for (auto PD : PrototypeDescriptors) {
906bdd1243dSDimitry Andric     auto T = TypeCache.computeType(Type, Log2LMUL, PD);
90781ad6265SDimitry Andric     SuffixStrs.push_back((*T)->getShortStr());
90881ad6265SDimitry Andric   }
90981ad6265SDimitry Andric   return join(SuffixStrs, "_");
91081ad6265SDimitry Andric }
91181ad6265SDimitry Andric 
912bdd1243dSDimitry Andric llvm::SmallVector<PrototypeDescriptor> RVVIntrinsic::computeBuiltinTypes(
913bdd1243dSDimitry Andric     llvm::ArrayRef<PrototypeDescriptor> Prototype, bool IsMasked,
914bdd1243dSDimitry Andric     bool HasMaskedOffOperand, bool HasVL, unsigned NF,
915bdd1243dSDimitry Andric     PolicyScheme DefaultScheme, Policy PolicyAttrs) {
916972a253aSDimitry Andric   SmallVector<PrototypeDescriptor> NewPrototype(Prototype.begin(),
917972a253aSDimitry Andric                                                 Prototype.end());
918bdd1243dSDimitry Andric   bool HasPassthruOp = DefaultScheme == PolicyScheme::HasPassthruOperand;
919972a253aSDimitry Andric   if (IsMasked) {
920bdd1243dSDimitry Andric     // If HasMaskedOffOperand, insert result type as first input operand if
921bdd1243dSDimitry Andric     // need.
922bdd1243dSDimitry Andric     if (HasMaskedOffOperand && !PolicyAttrs.isTAMAPolicy()) {
923972a253aSDimitry Andric       if (NF == 1) {
924972a253aSDimitry Andric         NewPrototype.insert(NewPrototype.begin() + 1, NewPrototype[0]);
925bdd1243dSDimitry Andric       } else if (NF > 1) {
926972a253aSDimitry Andric         // Convert
927972a253aSDimitry Andric         // (void, op0 address, op1 address, ...)
928972a253aSDimitry Andric         // to
929972a253aSDimitry Andric         // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
930972a253aSDimitry Andric         PrototypeDescriptor MaskoffType = NewPrototype[1];
931972a253aSDimitry Andric         MaskoffType.TM &= ~static_cast<uint8_t>(TypeModifier::Pointer);
932bdd1243dSDimitry Andric         NewPrototype.insert(NewPrototype.begin() + NF + 1, NF, MaskoffType);
933972a253aSDimitry Andric       }
934972a253aSDimitry Andric     }
935972a253aSDimitry Andric     if (HasMaskedOffOperand && NF > 1) {
936972a253aSDimitry Andric       // Convert
937972a253aSDimitry Andric       // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
938972a253aSDimitry Andric       // to
939972a253aSDimitry Andric       // (void, op0 address, op1 address, ..., mask, maskedoff0, maskedoff1,
940972a253aSDimitry Andric       // ...)
941972a253aSDimitry Andric       NewPrototype.insert(NewPrototype.begin() + NF + 1,
942972a253aSDimitry Andric                           PrototypeDescriptor::Mask);
943972a253aSDimitry Andric     } else {
944972a253aSDimitry Andric       // If IsMasked, insert PrototypeDescriptor:Mask as first input operand.
945972a253aSDimitry Andric       NewPrototype.insert(NewPrototype.begin() + 1, PrototypeDescriptor::Mask);
946972a253aSDimitry Andric     }
947bdd1243dSDimitry Andric   } else {
948bdd1243dSDimitry Andric     if (NF == 1) {
949bdd1243dSDimitry Andric       if (PolicyAttrs.isTUPolicy() && HasPassthruOp)
950bdd1243dSDimitry Andric         NewPrototype.insert(NewPrototype.begin(), NewPrototype[0]);
951bdd1243dSDimitry Andric     } else if (PolicyAttrs.isTUPolicy() && HasPassthruOp) {
952bdd1243dSDimitry Andric       // NF > 1 cases for segment load operations.
953bdd1243dSDimitry Andric       // Convert
954bdd1243dSDimitry Andric       // (void, op0 address, op1 address, ...)
955bdd1243dSDimitry Andric       // to
956bdd1243dSDimitry Andric       // (void, op0 address, op1 address, maskedoff0, maskedoff1, ...)
957bdd1243dSDimitry Andric       PrototypeDescriptor MaskoffType = Prototype[1];
958bdd1243dSDimitry Andric       MaskoffType.TM &= ~static_cast<uint8_t>(TypeModifier::Pointer);
959bdd1243dSDimitry Andric       NewPrototype.insert(NewPrototype.begin() + NF + 1, NF, MaskoffType);
960bdd1243dSDimitry Andric     }
961972a253aSDimitry Andric  }
962972a253aSDimitry Andric 
963972a253aSDimitry Andric   // If HasVL, append PrototypeDescriptor:VL to last operand
964972a253aSDimitry Andric   if (HasVL)
965972a253aSDimitry Andric     NewPrototype.push_back(PrototypeDescriptor::VL);
966972a253aSDimitry Andric   return NewPrototype;
967972a253aSDimitry Andric }
968972a253aSDimitry Andric 
969*1ac55f4cSDimitry Andric llvm::SmallVector<Policy> RVVIntrinsic::getSupportedUnMaskedPolicies() {
970*1ac55f4cSDimitry Andric   return {Policy(Policy::PolicyType::Undisturbed)}; // TU
971bdd1243dSDimitry Andric }
972bdd1243dSDimitry Andric 
973bdd1243dSDimitry Andric llvm::SmallVector<Policy>
974bdd1243dSDimitry Andric RVVIntrinsic::getSupportedMaskedPolicies(bool HasTailPolicy,
975bdd1243dSDimitry Andric                                          bool HasMaskPolicy) {
976bdd1243dSDimitry Andric   if (HasTailPolicy && HasMaskPolicy)
977*1ac55f4cSDimitry Andric     return {Policy(Policy::PolicyType::Undisturbed,
978*1ac55f4cSDimitry Andric                    Policy::PolicyType::Agnostic), // TUM
979*1ac55f4cSDimitry Andric             Policy(Policy::PolicyType::Undisturbed,
980*1ac55f4cSDimitry Andric                    Policy::PolicyType::Undisturbed), // TUMU
981*1ac55f4cSDimitry Andric             Policy(Policy::PolicyType::Agnostic,
982*1ac55f4cSDimitry Andric                    Policy::PolicyType::Undisturbed)}; // MU
983bdd1243dSDimitry Andric   if (HasTailPolicy && !HasMaskPolicy)
984bdd1243dSDimitry Andric     return {Policy(Policy::PolicyType::Undisturbed,
985*1ac55f4cSDimitry Andric                    Policy::PolicyType::Agnostic)}; // TU
986bdd1243dSDimitry Andric   if (!HasTailPolicy && HasMaskPolicy)
987*1ac55f4cSDimitry Andric     return {Policy(Policy::PolicyType::Agnostic,
988*1ac55f4cSDimitry Andric                    Policy::PolicyType::Undisturbed)}; // MU
989bdd1243dSDimitry Andric   llvm_unreachable("An RVV instruction should not be without both tail policy "
990bdd1243dSDimitry Andric                    "and mask policy");
991bdd1243dSDimitry Andric }
992bdd1243dSDimitry Andric 
993bdd1243dSDimitry Andric void RVVIntrinsic::updateNamesAndPolicy(bool IsMasked, bool HasPolicy,
994bdd1243dSDimitry Andric                                         std::string &Name,
995bdd1243dSDimitry Andric                                         std::string &BuiltinName,
996bdd1243dSDimitry Andric                                         std::string &OverloadedName,
997bdd1243dSDimitry Andric                                         Policy &PolicyAttrs) {
998bdd1243dSDimitry Andric 
999bdd1243dSDimitry Andric   auto appendPolicySuffix = [&](const std::string &suffix) {
1000bdd1243dSDimitry Andric     Name += suffix;
1001bdd1243dSDimitry Andric     BuiltinName += suffix;
1002bdd1243dSDimitry Andric     OverloadedName += suffix;
1003bdd1243dSDimitry Andric   };
1004bdd1243dSDimitry Andric 
1005*1ac55f4cSDimitry Andric   // This follows the naming guideline under riscv-c-api-doc to add the
1006*1ac55f4cSDimitry Andric   // `__riscv_` suffix for all RVV intrinsics.
1007*1ac55f4cSDimitry Andric   Name = "__riscv_" + Name;
1008*1ac55f4cSDimitry Andric   OverloadedName = "__riscv_" + OverloadedName;
1009*1ac55f4cSDimitry Andric 
1010bdd1243dSDimitry Andric   if (IsMasked) {
1011*1ac55f4cSDimitry Andric     if (PolicyAttrs.isTUMUPolicy())
1012*1ac55f4cSDimitry Andric       appendPolicySuffix("_tumu");
1013*1ac55f4cSDimitry Andric     else if (PolicyAttrs.isTUMAPolicy())
1014*1ac55f4cSDimitry Andric       appendPolicySuffix("_tum");
1015*1ac55f4cSDimitry Andric     else if (PolicyAttrs.isTAMUPolicy())
1016*1ac55f4cSDimitry Andric       appendPolicySuffix("_mu");
1017*1ac55f4cSDimitry Andric     else if (PolicyAttrs.isTAMAPolicy()) {
1018bdd1243dSDimitry Andric       Name += "_m";
1019bdd1243dSDimitry Andric       if (HasPolicy)
1020bdd1243dSDimitry Andric         BuiltinName += "_tama";
1021bdd1243dSDimitry Andric       else
1022bdd1243dSDimitry Andric         BuiltinName += "_m";
1023*1ac55f4cSDimitry Andric     } else
1024bdd1243dSDimitry Andric       llvm_unreachable("Unhandled policy condition");
1025bdd1243dSDimitry Andric   } else {
1026bdd1243dSDimitry Andric     if (PolicyAttrs.isTUPolicy())
1027bdd1243dSDimitry Andric       appendPolicySuffix("_tu");
1028*1ac55f4cSDimitry Andric     else if (PolicyAttrs.isTAPolicy()) {
1029*1ac55f4cSDimitry Andric       if (HasPolicy)
1030*1ac55f4cSDimitry Andric         BuiltinName += "_ta";
1031*1ac55f4cSDimitry Andric     } else
1032bdd1243dSDimitry Andric       llvm_unreachable("Unhandled policy condition");
1033bdd1243dSDimitry Andric   }
1034bdd1243dSDimitry Andric }
1035bdd1243dSDimitry Andric 
103681ad6265SDimitry Andric SmallVector<PrototypeDescriptor> parsePrototypes(StringRef Prototypes) {
103781ad6265SDimitry Andric   SmallVector<PrototypeDescriptor> PrototypeDescriptors;
103881ad6265SDimitry Andric   const StringRef Primaries("evwqom0ztul");
103981ad6265SDimitry Andric   while (!Prototypes.empty()) {
104081ad6265SDimitry Andric     size_t Idx = 0;
104181ad6265SDimitry Andric     // Skip over complex prototype because it could contain primitive type
104281ad6265SDimitry Andric     // character.
104381ad6265SDimitry Andric     if (Prototypes[0] == '(')
104481ad6265SDimitry Andric       Idx = Prototypes.find_first_of(')');
104581ad6265SDimitry Andric     Idx = Prototypes.find_first_of(Primaries, Idx);
104681ad6265SDimitry Andric     assert(Idx != StringRef::npos);
104781ad6265SDimitry Andric     auto PD = PrototypeDescriptor::parsePrototypeDescriptor(
104881ad6265SDimitry Andric         Prototypes.slice(0, Idx + 1));
104981ad6265SDimitry Andric     if (!PD)
105081ad6265SDimitry Andric       llvm_unreachable("Error during parsing prototype.");
105181ad6265SDimitry Andric     PrototypeDescriptors.push_back(*PD);
105281ad6265SDimitry Andric     Prototypes = Prototypes.drop_front(Idx + 1);
105381ad6265SDimitry Andric   }
105481ad6265SDimitry Andric   return PrototypeDescriptors;
105581ad6265SDimitry Andric }
105681ad6265SDimitry Andric 
1057972a253aSDimitry Andric raw_ostream &operator<<(raw_ostream &OS, const RVVIntrinsicRecord &Record) {
1058972a253aSDimitry Andric   OS << "{";
1059972a253aSDimitry Andric   OS << "\"" << Record.Name << "\",";
1060972a253aSDimitry Andric   if (Record.OverloadedName == nullptr ||
1061972a253aSDimitry Andric       StringRef(Record.OverloadedName).empty())
1062972a253aSDimitry Andric     OS << "nullptr,";
1063972a253aSDimitry Andric   else
1064972a253aSDimitry Andric     OS << "\"" << Record.OverloadedName << "\",";
1065972a253aSDimitry Andric   OS << Record.PrototypeIndex << ",";
1066972a253aSDimitry Andric   OS << Record.SuffixIndex << ",";
1067972a253aSDimitry Andric   OS << Record.OverloadedSuffixIndex << ",";
1068972a253aSDimitry Andric   OS << (int)Record.PrototypeLength << ",";
1069972a253aSDimitry Andric   OS << (int)Record.SuffixLength << ",";
1070972a253aSDimitry Andric   OS << (int)Record.OverloadedSuffixSize << ",";
1071972a253aSDimitry Andric   OS << (int)Record.RequiredExtensions << ",";
1072972a253aSDimitry Andric   OS << (int)Record.TypeRangeMask << ",";
1073972a253aSDimitry Andric   OS << (int)Record.Log2LMULMask << ",";
1074972a253aSDimitry Andric   OS << (int)Record.NF << ",";
1075972a253aSDimitry Andric   OS << (int)Record.HasMasked << ",";
1076972a253aSDimitry Andric   OS << (int)Record.HasVL << ",";
1077972a253aSDimitry Andric   OS << (int)Record.HasMaskedOffOperand << ",";
1078bdd1243dSDimitry Andric   OS << (int)Record.HasTailPolicy << ",";
1079bdd1243dSDimitry Andric   OS << (int)Record.HasMaskPolicy << ",";
1080bdd1243dSDimitry Andric   OS << (int)Record.UnMaskedPolicyScheme << ",";
1081bdd1243dSDimitry Andric   OS << (int)Record.MaskedPolicyScheme << ",";
1082972a253aSDimitry Andric   OS << "},\n";
1083972a253aSDimitry Andric   return OS;
1084972a253aSDimitry Andric }
1085972a253aSDimitry Andric 
108681ad6265SDimitry Andric } // end namespace RISCV
108781ad6265SDimitry Andric } // end namespace clang
1088