xref: /freebsd-src/contrib/llvm-project/clang/utils/TableGen/RISCVVEmitter.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
1fe6060f1SDimitry Andric //===- RISCVVEmitter.cpp - Generate riscv_vector.h for use with clang -----===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric //
9fe6060f1SDimitry Andric // This tablegen backend is responsible for emitting riscv_vector.h which
10fe6060f1SDimitry Andric // includes a declaration and definition of each intrinsic functions specified
11fe6060f1SDimitry Andric // in https://github.com/riscv/rvv-intrinsic-doc.
12fe6060f1SDimitry Andric //
13fe6060f1SDimitry Andric // See also the documentation in include/clang/Basic/riscv_vector.td.
14fe6060f1SDimitry Andric //
15fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
16fe6060f1SDimitry Andric 
17fe6060f1SDimitry Andric #include "llvm/ADT/ArrayRef.h"
18fe6060f1SDimitry Andric #include "llvm/ADT/SmallSet.h"
19fe6060f1SDimitry Andric #include "llvm/ADT/StringExtras.h"
20fe6060f1SDimitry Andric #include "llvm/ADT/StringMap.h"
21fe6060f1SDimitry Andric #include "llvm/ADT/StringSet.h"
22fe6060f1SDimitry Andric #include "llvm/ADT/Twine.h"
23fe6060f1SDimitry Andric #include "llvm/TableGen/Error.h"
24fe6060f1SDimitry Andric #include "llvm/TableGen/Record.h"
25fe6060f1SDimitry Andric #include <numeric>
26fe6060f1SDimitry Andric 
27fe6060f1SDimitry Andric using namespace llvm;
28fe6060f1SDimitry Andric using BasicType = char;
29fe6060f1SDimitry Andric using VScaleVal = Optional<unsigned>;
30fe6060f1SDimitry Andric 
31fe6060f1SDimitry Andric namespace {
32fe6060f1SDimitry Andric 
33fe6060f1SDimitry Andric // Exponential LMUL
34fe6060f1SDimitry Andric struct LMULType {
35fe6060f1SDimitry Andric   int Log2LMUL;
36fe6060f1SDimitry Andric   LMULType(int Log2LMUL);
37fe6060f1SDimitry Andric   // Return the C/C++ string representation of LMUL
38fe6060f1SDimitry Andric   std::string str() const;
39fe6060f1SDimitry Andric   Optional<unsigned> getScale(unsigned ElementBitwidth) const;
40fe6060f1SDimitry Andric   void MulLog2LMUL(int Log2LMUL);
41fe6060f1SDimitry Andric   LMULType &operator*=(uint32_t RHS);
42fe6060f1SDimitry Andric };
43fe6060f1SDimitry Andric 
44fe6060f1SDimitry Andric // This class is compact representation of a valid and invalid RVVType.
45fe6060f1SDimitry Andric class RVVType {
46fe6060f1SDimitry Andric   enum ScalarTypeKind : uint32_t {
47fe6060f1SDimitry Andric     Void,
48fe6060f1SDimitry Andric     Size_t,
49fe6060f1SDimitry Andric     Ptrdiff_t,
50fe6060f1SDimitry Andric     UnsignedLong,
51fe6060f1SDimitry Andric     SignedLong,
52fe6060f1SDimitry Andric     Boolean,
53fe6060f1SDimitry Andric     SignedInteger,
54fe6060f1SDimitry Andric     UnsignedInteger,
55fe6060f1SDimitry Andric     Float,
56fe6060f1SDimitry Andric     Invalid,
57fe6060f1SDimitry Andric   };
58fe6060f1SDimitry Andric   BasicType BT;
59fe6060f1SDimitry Andric   ScalarTypeKind ScalarType = Invalid;
60fe6060f1SDimitry Andric   LMULType LMUL;
61fe6060f1SDimitry Andric   bool IsPointer = false;
62fe6060f1SDimitry Andric   // IsConstant indices are "int", but have the constant expression.
63fe6060f1SDimitry Andric   bool IsImmediate = false;
64fe6060f1SDimitry Andric   // Const qualifier for pointer to const object or object of const type.
65fe6060f1SDimitry Andric   bool IsConstant = false;
66fe6060f1SDimitry Andric   unsigned ElementBitwidth = 0;
67fe6060f1SDimitry Andric   VScaleVal Scale = 0;
68fe6060f1SDimitry Andric   bool Valid;
69fe6060f1SDimitry Andric 
70fe6060f1SDimitry Andric   std::string BuiltinStr;
71fe6060f1SDimitry Andric   std::string ClangBuiltinStr;
72fe6060f1SDimitry Andric   std::string Str;
73fe6060f1SDimitry Andric   std::string ShortStr;
74fe6060f1SDimitry Andric 
75fe6060f1SDimitry Andric public:
76fe6060f1SDimitry Andric   RVVType() : RVVType(BasicType(), 0, StringRef()) {}
77fe6060f1SDimitry Andric   RVVType(BasicType BT, int Log2LMUL, StringRef prototype);
78fe6060f1SDimitry Andric 
79fe6060f1SDimitry Andric   // Return the string representation of a type, which is an encoded string for
80fe6060f1SDimitry Andric   // passing to the BUILTIN() macro in Builtins.def.
81fe6060f1SDimitry Andric   const std::string &getBuiltinStr() const { return BuiltinStr; }
82fe6060f1SDimitry Andric 
83*349cc55cSDimitry Andric   // Return the clang builtin type for RVV vector type which are used in the
84fe6060f1SDimitry Andric   // riscv_vector.h header file.
85fe6060f1SDimitry Andric   const std::string &getClangBuiltinStr() const { return ClangBuiltinStr; }
86fe6060f1SDimitry Andric 
87fe6060f1SDimitry Andric   // Return the C/C++ string representation of a type for use in the
88fe6060f1SDimitry Andric   // riscv_vector.h header file.
89fe6060f1SDimitry Andric   const std::string &getTypeStr() const { return Str; }
90fe6060f1SDimitry Andric 
91fe6060f1SDimitry Andric   // Return the short name of a type for C/C++ name suffix.
92fe6060f1SDimitry Andric   const std::string &getShortStr() {
93fe6060f1SDimitry Andric     // Not all types are used in short name, so compute the short name by
94fe6060f1SDimitry Andric     // demanded.
95fe6060f1SDimitry Andric     if (ShortStr.empty())
96fe6060f1SDimitry Andric       initShortStr();
97fe6060f1SDimitry Andric     return ShortStr;
98fe6060f1SDimitry Andric   }
99fe6060f1SDimitry Andric 
100fe6060f1SDimitry Andric   bool isValid() const { return Valid; }
101fe6060f1SDimitry Andric   bool isScalar() const { return Scale.hasValue() && Scale.getValue() == 0; }
102fe6060f1SDimitry Andric   bool isVector() const { return Scale.hasValue() && Scale.getValue() != 0; }
103fe6060f1SDimitry Andric   bool isFloat() const { return ScalarType == ScalarTypeKind::Float; }
104fe6060f1SDimitry Andric   bool isSignedInteger() const {
105fe6060f1SDimitry Andric     return ScalarType == ScalarTypeKind::SignedInteger;
106fe6060f1SDimitry Andric   }
107fe6060f1SDimitry Andric   bool isFloatVector(unsigned Width) const {
108fe6060f1SDimitry Andric     return isVector() && isFloat() && ElementBitwidth == Width;
109fe6060f1SDimitry Andric   }
110fe6060f1SDimitry Andric   bool isFloat(unsigned Width) const {
111fe6060f1SDimitry Andric     return isFloat() && ElementBitwidth == Width;
112fe6060f1SDimitry Andric   }
113fe6060f1SDimitry Andric 
114fe6060f1SDimitry Andric private:
115fe6060f1SDimitry Andric   // Verify RVV vector type and set Valid.
116fe6060f1SDimitry Andric   bool verifyType() const;
117fe6060f1SDimitry Andric 
118fe6060f1SDimitry Andric   // Creates a type based on basic types of TypeRange
119fe6060f1SDimitry Andric   void applyBasicType();
120fe6060f1SDimitry Andric 
121fe6060f1SDimitry Andric   // Applies a prototype modifier to the current type. The result maybe an
122fe6060f1SDimitry Andric   // invalid type.
123fe6060f1SDimitry Andric   void applyModifier(StringRef prototype);
124fe6060f1SDimitry Andric 
125fe6060f1SDimitry Andric   // Compute and record a string for legal type.
126fe6060f1SDimitry Andric   void initBuiltinStr();
127fe6060f1SDimitry Andric   // Compute and record a builtin RVV vector type string.
128fe6060f1SDimitry Andric   void initClangBuiltinStr();
129fe6060f1SDimitry Andric   // Compute and record a type string for used in the header.
130fe6060f1SDimitry Andric   void initTypeStr();
131fe6060f1SDimitry Andric   // Compute and record a short name of a type for C/C++ name suffix.
132fe6060f1SDimitry Andric   void initShortStr();
133fe6060f1SDimitry Andric };
134fe6060f1SDimitry Andric 
135fe6060f1SDimitry Andric using RVVTypePtr = RVVType *;
136fe6060f1SDimitry Andric using RVVTypes = std::vector<RVVTypePtr>;
137fe6060f1SDimitry Andric 
138fe6060f1SDimitry Andric enum RISCVExtension : uint8_t {
139fe6060f1SDimitry Andric   Basic = 0,
140fe6060f1SDimitry Andric   F = 1 << 1,
141fe6060f1SDimitry Andric   D = 1 << 2,
142fe6060f1SDimitry Andric   Zfh = 1 << 3,
143*349cc55cSDimitry Andric   Zvlsseg = 1 << 4,
144fe6060f1SDimitry Andric };
145fe6060f1SDimitry Andric 
146fe6060f1SDimitry Andric // TODO refactor RVVIntrinsic class design after support all intrinsic
147fe6060f1SDimitry Andric // combination. This represents an instantiation of an intrinsic with a
148fe6060f1SDimitry Andric // particular type and prototype
149fe6060f1SDimitry Andric class RVVIntrinsic {
150fe6060f1SDimitry Andric 
151fe6060f1SDimitry Andric private:
152*349cc55cSDimitry Andric   std::string BuiltinName; // Builtin name
153*349cc55cSDimitry Andric   std::string Name;        // C intrinsic name.
154fe6060f1SDimitry Andric   std::string MangledName;
155fe6060f1SDimitry Andric   std::string IRName;
156fe6060f1SDimitry Andric   bool IsMask;
157fe6060f1SDimitry Andric   bool HasVL;
158*349cc55cSDimitry Andric   bool HasPolicy;
159fe6060f1SDimitry Andric   bool HasNoMaskedOverloaded;
160fe6060f1SDimitry Andric   bool HasAutoDef; // There is automiatic definition in header
161fe6060f1SDimitry Andric   std::string ManualCodegen;
162fe6060f1SDimitry Andric   RVVTypePtr OutputType; // Builtin output type
163fe6060f1SDimitry Andric   RVVTypes InputTypes;   // Builtin input types
164fe6060f1SDimitry Andric   // The types we use to obtain the specific LLVM intrinsic. They are index of
165fe6060f1SDimitry Andric   // InputTypes. -1 means the return type.
166fe6060f1SDimitry Andric   std::vector<int64_t> IntrinsicTypes;
167fe6060f1SDimitry Andric   uint8_t RISCVExtensions = 0;
168fe6060f1SDimitry Andric   unsigned NF = 1;
169fe6060f1SDimitry Andric 
170fe6060f1SDimitry Andric public:
171fe6060f1SDimitry Andric   RVVIntrinsic(StringRef Name, StringRef Suffix, StringRef MangledName,
172*349cc55cSDimitry Andric                StringRef MangledSuffix, StringRef IRName, bool IsMask,
173*349cc55cSDimitry Andric                bool HasMaskedOffOperand, bool HasVL, bool HasPolicy,
174fe6060f1SDimitry Andric                bool HasNoMaskedOverloaded, bool HasAutoDef,
175fe6060f1SDimitry Andric                StringRef ManualCodegen, const RVVTypes &Types,
176fe6060f1SDimitry Andric                const std::vector<int64_t> &IntrinsicTypes,
177fe6060f1SDimitry Andric                StringRef RequiredExtension, unsigned NF);
178fe6060f1SDimitry Andric   ~RVVIntrinsic() = default;
179fe6060f1SDimitry Andric 
180*349cc55cSDimitry Andric   StringRef getBuiltinName() const { return BuiltinName; }
181fe6060f1SDimitry Andric   StringRef getName() const { return Name; }
182fe6060f1SDimitry Andric   StringRef getMangledName() const { return MangledName; }
183fe6060f1SDimitry Andric   bool hasVL() const { return HasVL; }
184*349cc55cSDimitry Andric   bool hasPolicy() const { return HasPolicy; }
185fe6060f1SDimitry Andric   bool hasNoMaskedOverloaded() const { return HasNoMaskedOverloaded; }
186fe6060f1SDimitry Andric   bool hasManualCodegen() const { return !ManualCodegen.empty(); }
187fe6060f1SDimitry Andric   bool hasAutoDef() const { return HasAutoDef; }
188fe6060f1SDimitry Andric   bool isMask() const { return IsMask; }
189fe6060f1SDimitry Andric   StringRef getIRName() const { return IRName; }
190fe6060f1SDimitry Andric   StringRef getManualCodegen() const { return ManualCodegen; }
191fe6060f1SDimitry Andric   uint8_t getRISCVExtensions() const { return RISCVExtensions; }
192fe6060f1SDimitry Andric   unsigned getNF() const { return NF; }
193*349cc55cSDimitry Andric   const std::vector<int64_t> &getIntrinsicTypes() const {
194*349cc55cSDimitry Andric     return IntrinsicTypes;
195*349cc55cSDimitry Andric   }
196fe6060f1SDimitry Andric 
197fe6060f1SDimitry Andric   // Return the type string for a BUILTIN() macro in Builtins.def.
198fe6060f1SDimitry Andric   std::string getBuiltinTypeStr() const;
199fe6060f1SDimitry Andric 
200fe6060f1SDimitry Andric   // Emit the code block for switch body in EmitRISCVBuiltinExpr, it should
201fe6060f1SDimitry Andric   // init the RVVIntrinsic ID and IntrinsicTypes.
202fe6060f1SDimitry Andric   void emitCodeGenSwitchBody(raw_ostream &o) const;
203fe6060f1SDimitry Andric 
204fe6060f1SDimitry Andric   // Emit the macros for mapping C/C++ intrinsic function to builtin functions.
205*349cc55cSDimitry Andric   void emitIntrinsicFuncDef(raw_ostream &o) const;
206fe6060f1SDimitry Andric 
207fe6060f1SDimitry Andric   // Emit the mangled function definition.
208fe6060f1SDimitry Andric   void emitMangledFuncDef(raw_ostream &o) const;
209fe6060f1SDimitry Andric };
210fe6060f1SDimitry Andric 
211fe6060f1SDimitry Andric class RVVEmitter {
212fe6060f1SDimitry Andric private:
213fe6060f1SDimitry Andric   RecordKeeper &Records;
214fe6060f1SDimitry Andric   std::string HeaderCode;
215fe6060f1SDimitry Andric   // Concat BasicType, LMUL and Proto as key
216fe6060f1SDimitry Andric   StringMap<RVVType> LegalTypes;
217fe6060f1SDimitry Andric   StringSet<> IllegalTypes;
218fe6060f1SDimitry Andric 
219fe6060f1SDimitry Andric public:
220fe6060f1SDimitry Andric   RVVEmitter(RecordKeeper &R) : Records(R) {}
221fe6060f1SDimitry Andric 
222fe6060f1SDimitry Andric   /// Emit riscv_vector.h
223fe6060f1SDimitry Andric   void createHeader(raw_ostream &o);
224fe6060f1SDimitry Andric 
225fe6060f1SDimitry Andric   /// Emit all the __builtin prototypes and code needed by Sema.
226fe6060f1SDimitry Andric   void createBuiltins(raw_ostream &o);
227fe6060f1SDimitry Andric 
228fe6060f1SDimitry Andric   /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
229fe6060f1SDimitry Andric   void createCodeGen(raw_ostream &o);
230fe6060f1SDimitry Andric 
231fe6060f1SDimitry Andric   std::string getSuffixStr(char Type, int Log2LMUL, StringRef Prototypes);
232fe6060f1SDimitry Andric 
233fe6060f1SDimitry Andric private:
234fe6060f1SDimitry Andric   /// Create all intrinsics and add them to \p Out
235fe6060f1SDimitry Andric   void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out);
236*349cc55cSDimitry Andric   /// Create Headers and add them to \p Out
237*349cc55cSDimitry Andric   void createRVVHeaders(raw_ostream &OS);
238fe6060f1SDimitry Andric   /// Compute output and input types by applying different config (basic type
239fe6060f1SDimitry Andric   /// and LMUL with type transformers). It also record result of type in legal
240fe6060f1SDimitry Andric   /// or illegal set to avoid compute the  same config again. The result maybe
241fe6060f1SDimitry Andric   /// have illegal RVVType.
242fe6060f1SDimitry Andric   Optional<RVVTypes> computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
243fe6060f1SDimitry Andric                                   ArrayRef<std::string> PrototypeSeq);
244fe6060f1SDimitry Andric   Optional<RVVTypePtr> computeType(BasicType BT, int Log2LMUL, StringRef Proto);
245fe6060f1SDimitry Andric 
246fe6060f1SDimitry Andric   /// Emit Acrh predecessor definitions and body, assume the element of Defs are
247fe6060f1SDimitry Andric   /// sorted by extension.
248fe6060f1SDimitry Andric   void emitArchMacroAndBody(
249fe6060f1SDimitry Andric       std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &o,
250fe6060f1SDimitry Andric       std::function<void(raw_ostream &, const RVVIntrinsic &)>);
251fe6060f1SDimitry Andric 
252fe6060f1SDimitry Andric   // Emit the architecture preprocessor definitions. Return true when emits
253fe6060f1SDimitry Andric   // non-empty string.
254fe6060f1SDimitry Andric   bool emitExtDefStr(uint8_t Extensions, raw_ostream &o);
255fe6060f1SDimitry Andric   // Slice Prototypes string into sub prototype string and process each sub
256fe6060f1SDimitry Andric   // prototype string individually in the Handler.
257fe6060f1SDimitry Andric   void parsePrototypes(StringRef Prototypes,
258fe6060f1SDimitry Andric                        std::function<void(StringRef)> Handler);
259fe6060f1SDimitry Andric };
260fe6060f1SDimitry Andric 
261fe6060f1SDimitry Andric } // namespace
262fe6060f1SDimitry Andric 
263fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
264fe6060f1SDimitry Andric // Type implementation
265fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
266fe6060f1SDimitry Andric 
267fe6060f1SDimitry Andric LMULType::LMULType(int NewLog2LMUL) {
268fe6060f1SDimitry Andric   // Check Log2LMUL is -3, -2, -1, 0, 1, 2, 3
269fe6060f1SDimitry Andric   assert(NewLog2LMUL <= 3 && NewLog2LMUL >= -3 && "Bad LMUL number!");
270fe6060f1SDimitry Andric   Log2LMUL = NewLog2LMUL;
271fe6060f1SDimitry Andric }
272fe6060f1SDimitry Andric 
273fe6060f1SDimitry Andric std::string LMULType::str() const {
274fe6060f1SDimitry Andric   if (Log2LMUL < 0)
275fe6060f1SDimitry Andric     return "mf" + utostr(1ULL << (-Log2LMUL));
276fe6060f1SDimitry Andric   return "m" + utostr(1ULL << Log2LMUL);
277fe6060f1SDimitry Andric }
278fe6060f1SDimitry Andric 
279fe6060f1SDimitry Andric VScaleVal LMULType::getScale(unsigned ElementBitwidth) const {
280fe6060f1SDimitry Andric   int Log2ScaleResult = 0;
281fe6060f1SDimitry Andric   switch (ElementBitwidth) {
282fe6060f1SDimitry Andric   default:
283fe6060f1SDimitry Andric     break;
284fe6060f1SDimitry Andric   case 8:
285fe6060f1SDimitry Andric     Log2ScaleResult = Log2LMUL + 3;
286fe6060f1SDimitry Andric     break;
287fe6060f1SDimitry Andric   case 16:
288fe6060f1SDimitry Andric     Log2ScaleResult = Log2LMUL + 2;
289fe6060f1SDimitry Andric     break;
290fe6060f1SDimitry Andric   case 32:
291fe6060f1SDimitry Andric     Log2ScaleResult = Log2LMUL + 1;
292fe6060f1SDimitry Andric     break;
293fe6060f1SDimitry Andric   case 64:
294fe6060f1SDimitry Andric     Log2ScaleResult = Log2LMUL;
295fe6060f1SDimitry Andric     break;
296fe6060f1SDimitry Andric   }
297fe6060f1SDimitry Andric   // Illegal vscale result would be less than 1
298fe6060f1SDimitry Andric   if (Log2ScaleResult < 0)
299fe6060f1SDimitry Andric     return None;
300fe6060f1SDimitry Andric   return 1 << Log2ScaleResult;
301fe6060f1SDimitry Andric }
302fe6060f1SDimitry Andric 
303fe6060f1SDimitry Andric void LMULType::MulLog2LMUL(int log2LMUL) { Log2LMUL += log2LMUL; }
304fe6060f1SDimitry Andric 
305fe6060f1SDimitry Andric LMULType &LMULType::operator*=(uint32_t RHS) {
306fe6060f1SDimitry Andric   assert(isPowerOf2_32(RHS));
307fe6060f1SDimitry Andric   this->Log2LMUL = this->Log2LMUL + Log2_32(RHS);
308fe6060f1SDimitry Andric   return *this;
309fe6060f1SDimitry Andric }
310fe6060f1SDimitry Andric 
311fe6060f1SDimitry Andric RVVType::RVVType(BasicType BT, int Log2LMUL, StringRef prototype)
312fe6060f1SDimitry Andric     : BT(BT), LMUL(LMULType(Log2LMUL)) {
313fe6060f1SDimitry Andric   applyBasicType();
314fe6060f1SDimitry Andric   applyModifier(prototype);
315fe6060f1SDimitry Andric   Valid = verifyType();
316fe6060f1SDimitry Andric   if (Valid) {
317fe6060f1SDimitry Andric     initBuiltinStr();
318fe6060f1SDimitry Andric     initTypeStr();
319fe6060f1SDimitry Andric     if (isVector()) {
320fe6060f1SDimitry Andric       initClangBuiltinStr();
321fe6060f1SDimitry Andric     }
322fe6060f1SDimitry Andric   }
323fe6060f1SDimitry Andric }
324fe6060f1SDimitry Andric 
325fe6060f1SDimitry Andric // clang-format off
326fe6060f1SDimitry Andric // boolean type are encoded the ratio of n (SEW/LMUL)
327fe6060f1SDimitry Andric // SEW/LMUL | 1         | 2         | 4         | 8        | 16        | 32        | 64
328fe6060f1SDimitry Andric // c type   | vbool64_t | vbool32_t | vbool16_t | vbool8_t | vbool4_t  | vbool2_t  | vbool1_t
329fe6060f1SDimitry Andric // IR type  | nxv1i1    | nxv2i1    | nxv4i1    | nxv8i1   | nxv16i1   | nxv32i1   | nxv64i1
330fe6060f1SDimitry Andric 
331fe6060f1SDimitry Andric // type\lmul | 1/8    | 1/4      | 1/2     | 1       | 2        | 4        | 8
332fe6060f1SDimitry Andric // --------  |------  | -------- | ------- | ------- | -------- | -------- | --------
333fe6060f1SDimitry Andric // i64       | N/A    | N/A      | N/A     | nxv1i64 | nxv2i64  | nxv4i64  | nxv8i64
334fe6060f1SDimitry Andric // i32       | N/A    | N/A      | nxv1i32 | nxv2i32 | nxv4i32  | nxv8i32  | nxv16i32
335fe6060f1SDimitry Andric // i16       | N/A    | nxv1i16  | nxv2i16 | nxv4i16 | nxv8i16  | nxv16i16 | nxv32i16
336fe6060f1SDimitry Andric // i8        | nxv1i8 | nxv2i8   | nxv4i8  | nxv8i8  | nxv16i8  | nxv32i8  | nxv64i8
337fe6060f1SDimitry Andric // double    | N/A    | N/A      | N/A     | nxv1f64 | nxv2f64  | nxv4f64  | nxv8f64
338fe6060f1SDimitry Andric // float     | N/A    | N/A      | nxv1f32 | nxv2f32 | nxv4f32  | nxv8f32  | nxv16f32
339fe6060f1SDimitry Andric // half      | N/A    | nxv1f16  | nxv2f16 | nxv4f16 | nxv8f16  | nxv16f16 | nxv32f16
340fe6060f1SDimitry Andric // clang-format on
341fe6060f1SDimitry Andric 
342fe6060f1SDimitry Andric bool RVVType::verifyType() const {
343fe6060f1SDimitry Andric   if (ScalarType == Invalid)
344fe6060f1SDimitry Andric     return false;
345fe6060f1SDimitry Andric   if (isScalar())
346fe6060f1SDimitry Andric     return true;
347fe6060f1SDimitry Andric   if (!Scale.hasValue())
348fe6060f1SDimitry Andric     return false;
349fe6060f1SDimitry Andric   if (isFloat() && ElementBitwidth == 8)
350fe6060f1SDimitry Andric     return false;
351fe6060f1SDimitry Andric   unsigned V = Scale.getValue();
352fe6060f1SDimitry Andric   switch (ElementBitwidth) {
353fe6060f1SDimitry Andric   case 1:
354fe6060f1SDimitry Andric   case 8:
355fe6060f1SDimitry Andric     // Check Scale is 1,2,4,8,16,32,64
356fe6060f1SDimitry Andric     return (V <= 64 && isPowerOf2_32(V));
357fe6060f1SDimitry Andric   case 16:
358fe6060f1SDimitry Andric     // Check Scale is 1,2,4,8,16,32
359fe6060f1SDimitry Andric     return (V <= 32 && isPowerOf2_32(V));
360fe6060f1SDimitry Andric   case 32:
361fe6060f1SDimitry Andric     // Check Scale is 1,2,4,8,16
362fe6060f1SDimitry Andric     return (V <= 16 && isPowerOf2_32(V));
363fe6060f1SDimitry Andric   case 64:
364fe6060f1SDimitry Andric     // Check Scale is 1,2,4,8
365fe6060f1SDimitry Andric     return (V <= 8 && isPowerOf2_32(V));
366fe6060f1SDimitry Andric   }
367fe6060f1SDimitry Andric   return false;
368fe6060f1SDimitry Andric }
369fe6060f1SDimitry Andric 
370fe6060f1SDimitry Andric void RVVType::initBuiltinStr() {
371fe6060f1SDimitry Andric   assert(isValid() && "RVVType is invalid");
372fe6060f1SDimitry Andric   switch (ScalarType) {
373fe6060f1SDimitry Andric   case ScalarTypeKind::Void:
374fe6060f1SDimitry Andric     BuiltinStr = "v";
375fe6060f1SDimitry Andric     return;
376fe6060f1SDimitry Andric   case ScalarTypeKind::Size_t:
377fe6060f1SDimitry Andric     BuiltinStr = "z";
378fe6060f1SDimitry Andric     if (IsImmediate)
379fe6060f1SDimitry Andric       BuiltinStr = "I" + BuiltinStr;
380fe6060f1SDimitry Andric     if (IsPointer)
381fe6060f1SDimitry Andric       BuiltinStr += "*";
382fe6060f1SDimitry Andric     return;
383fe6060f1SDimitry Andric   case ScalarTypeKind::Ptrdiff_t:
384fe6060f1SDimitry Andric     BuiltinStr = "Y";
385fe6060f1SDimitry Andric     return;
386fe6060f1SDimitry Andric   case ScalarTypeKind::UnsignedLong:
387fe6060f1SDimitry Andric     BuiltinStr = "ULi";
388fe6060f1SDimitry Andric     return;
389fe6060f1SDimitry Andric   case ScalarTypeKind::SignedLong:
390fe6060f1SDimitry Andric     BuiltinStr = "Li";
391fe6060f1SDimitry Andric     return;
392fe6060f1SDimitry Andric   case ScalarTypeKind::Boolean:
393fe6060f1SDimitry Andric     assert(ElementBitwidth == 1);
394fe6060f1SDimitry Andric     BuiltinStr += "b";
395fe6060f1SDimitry Andric     break;
396fe6060f1SDimitry Andric   case ScalarTypeKind::SignedInteger:
397fe6060f1SDimitry Andric   case ScalarTypeKind::UnsignedInteger:
398fe6060f1SDimitry Andric     switch (ElementBitwidth) {
399fe6060f1SDimitry Andric     case 8:
400fe6060f1SDimitry Andric       BuiltinStr += "c";
401fe6060f1SDimitry Andric       break;
402fe6060f1SDimitry Andric     case 16:
403fe6060f1SDimitry Andric       BuiltinStr += "s";
404fe6060f1SDimitry Andric       break;
405fe6060f1SDimitry Andric     case 32:
406fe6060f1SDimitry Andric       BuiltinStr += "i";
407fe6060f1SDimitry Andric       break;
408fe6060f1SDimitry Andric     case 64:
409fe6060f1SDimitry Andric       BuiltinStr += "Wi";
410fe6060f1SDimitry Andric       break;
411fe6060f1SDimitry Andric     default:
412fe6060f1SDimitry Andric       llvm_unreachable("Unhandled ElementBitwidth!");
413fe6060f1SDimitry Andric     }
414fe6060f1SDimitry Andric     if (isSignedInteger())
415fe6060f1SDimitry Andric       BuiltinStr = "S" + BuiltinStr;
416fe6060f1SDimitry Andric     else
417fe6060f1SDimitry Andric       BuiltinStr = "U" + BuiltinStr;
418fe6060f1SDimitry Andric     break;
419fe6060f1SDimitry Andric   case ScalarTypeKind::Float:
420fe6060f1SDimitry Andric     switch (ElementBitwidth) {
421fe6060f1SDimitry Andric     case 16:
422fe6060f1SDimitry Andric       BuiltinStr += "x";
423fe6060f1SDimitry Andric       break;
424fe6060f1SDimitry Andric     case 32:
425fe6060f1SDimitry Andric       BuiltinStr += "f";
426fe6060f1SDimitry Andric       break;
427fe6060f1SDimitry Andric     case 64:
428fe6060f1SDimitry Andric       BuiltinStr += "d";
429fe6060f1SDimitry Andric       break;
430fe6060f1SDimitry Andric     default:
431fe6060f1SDimitry Andric       llvm_unreachable("Unhandled ElementBitwidth!");
432fe6060f1SDimitry Andric     }
433fe6060f1SDimitry Andric     break;
434fe6060f1SDimitry Andric   default:
435fe6060f1SDimitry Andric     llvm_unreachable("ScalarType is invalid!");
436fe6060f1SDimitry Andric   }
437fe6060f1SDimitry Andric   if (IsImmediate)
438fe6060f1SDimitry Andric     BuiltinStr = "I" + BuiltinStr;
439fe6060f1SDimitry Andric   if (isScalar()) {
440fe6060f1SDimitry Andric     if (IsConstant)
441fe6060f1SDimitry Andric       BuiltinStr += "C";
442fe6060f1SDimitry Andric     if (IsPointer)
443fe6060f1SDimitry Andric       BuiltinStr += "*";
444fe6060f1SDimitry Andric     return;
445fe6060f1SDimitry Andric   }
446fe6060f1SDimitry Andric   BuiltinStr = "q" + utostr(Scale.getValue()) + BuiltinStr;
447fe6060f1SDimitry Andric   // Pointer to vector types. Defined for Zvlsseg load intrinsics.
448fe6060f1SDimitry Andric   // Zvlsseg load intrinsics have pointer type arguments to store the loaded
449fe6060f1SDimitry Andric   // vector values.
450fe6060f1SDimitry Andric   if (IsPointer)
451fe6060f1SDimitry Andric     BuiltinStr += "*";
452fe6060f1SDimitry Andric }
453fe6060f1SDimitry Andric 
454fe6060f1SDimitry Andric void RVVType::initClangBuiltinStr() {
455fe6060f1SDimitry Andric   assert(isValid() && "RVVType is invalid");
456fe6060f1SDimitry Andric   assert(isVector() && "Handle Vector type only");
457fe6060f1SDimitry Andric 
458fe6060f1SDimitry Andric   ClangBuiltinStr = "__rvv_";
459fe6060f1SDimitry Andric   switch (ScalarType) {
460fe6060f1SDimitry Andric   case ScalarTypeKind::Boolean:
461fe6060f1SDimitry Andric     ClangBuiltinStr += "bool" + utostr(64 / Scale.getValue()) + "_t";
462fe6060f1SDimitry Andric     return;
463fe6060f1SDimitry Andric   case ScalarTypeKind::Float:
464fe6060f1SDimitry Andric     ClangBuiltinStr += "float";
465fe6060f1SDimitry Andric     break;
466fe6060f1SDimitry Andric   case ScalarTypeKind::SignedInteger:
467fe6060f1SDimitry Andric     ClangBuiltinStr += "int";
468fe6060f1SDimitry Andric     break;
469fe6060f1SDimitry Andric   case ScalarTypeKind::UnsignedInteger:
470fe6060f1SDimitry Andric     ClangBuiltinStr += "uint";
471fe6060f1SDimitry Andric     break;
472fe6060f1SDimitry Andric   default:
473fe6060f1SDimitry Andric     llvm_unreachable("ScalarTypeKind is invalid");
474fe6060f1SDimitry Andric   }
475fe6060f1SDimitry Andric   ClangBuiltinStr += utostr(ElementBitwidth) + LMUL.str() + "_t";
476fe6060f1SDimitry Andric }
477fe6060f1SDimitry Andric 
478fe6060f1SDimitry Andric void RVVType::initTypeStr() {
479fe6060f1SDimitry Andric   assert(isValid() && "RVVType is invalid");
480fe6060f1SDimitry Andric 
481fe6060f1SDimitry Andric   if (IsConstant)
482fe6060f1SDimitry Andric     Str += "const ";
483fe6060f1SDimitry Andric 
484fe6060f1SDimitry Andric   auto getTypeString = [&](StringRef TypeStr) {
485fe6060f1SDimitry Andric     if (isScalar())
486fe6060f1SDimitry Andric       return Twine(TypeStr + Twine(ElementBitwidth) + "_t").str();
487fe6060f1SDimitry Andric     return Twine("v" + TypeStr + Twine(ElementBitwidth) + LMUL.str() + "_t")
488fe6060f1SDimitry Andric         .str();
489fe6060f1SDimitry Andric   };
490fe6060f1SDimitry Andric 
491fe6060f1SDimitry Andric   switch (ScalarType) {
492fe6060f1SDimitry Andric   case ScalarTypeKind::Void:
493fe6060f1SDimitry Andric     Str = "void";
494fe6060f1SDimitry Andric     return;
495fe6060f1SDimitry Andric   case ScalarTypeKind::Size_t:
496fe6060f1SDimitry Andric     Str = "size_t";
497fe6060f1SDimitry Andric     if (IsPointer)
498fe6060f1SDimitry Andric       Str += " *";
499fe6060f1SDimitry Andric     return;
500fe6060f1SDimitry Andric   case ScalarTypeKind::Ptrdiff_t:
501fe6060f1SDimitry Andric     Str = "ptrdiff_t";
502fe6060f1SDimitry Andric     return;
503fe6060f1SDimitry Andric   case ScalarTypeKind::UnsignedLong:
504fe6060f1SDimitry Andric     Str = "unsigned long";
505fe6060f1SDimitry Andric     return;
506fe6060f1SDimitry Andric   case ScalarTypeKind::SignedLong:
507fe6060f1SDimitry Andric     Str = "long";
508fe6060f1SDimitry Andric     return;
509fe6060f1SDimitry Andric   case ScalarTypeKind::Boolean:
510fe6060f1SDimitry Andric     if (isScalar())
511fe6060f1SDimitry Andric       Str += "bool";
512fe6060f1SDimitry Andric     else
513fe6060f1SDimitry Andric       // Vector bool is special case, the formulate is
514fe6060f1SDimitry Andric       // `vbool<N>_t = MVT::nxv<64/N>i1` ex. vbool16_t = MVT::4i1
515fe6060f1SDimitry Andric       Str += "vbool" + utostr(64 / Scale.getValue()) + "_t";
516fe6060f1SDimitry Andric     break;
517fe6060f1SDimitry Andric   case ScalarTypeKind::Float:
518fe6060f1SDimitry Andric     if (isScalar()) {
519fe6060f1SDimitry Andric       if (ElementBitwidth == 64)
520fe6060f1SDimitry Andric         Str += "double";
521fe6060f1SDimitry Andric       else if (ElementBitwidth == 32)
522fe6060f1SDimitry Andric         Str += "float";
523fe6060f1SDimitry Andric       else if (ElementBitwidth == 16)
524fe6060f1SDimitry Andric         Str += "_Float16";
525fe6060f1SDimitry Andric       else
526fe6060f1SDimitry Andric         llvm_unreachable("Unhandled floating type.");
527fe6060f1SDimitry Andric     } else
528fe6060f1SDimitry Andric       Str += getTypeString("float");
529fe6060f1SDimitry Andric     break;
530fe6060f1SDimitry Andric   case ScalarTypeKind::SignedInteger:
531fe6060f1SDimitry Andric     Str += getTypeString("int");
532fe6060f1SDimitry Andric     break;
533fe6060f1SDimitry Andric   case ScalarTypeKind::UnsignedInteger:
534fe6060f1SDimitry Andric     Str += getTypeString("uint");
535fe6060f1SDimitry Andric     break;
536fe6060f1SDimitry Andric   default:
537fe6060f1SDimitry Andric     llvm_unreachable("ScalarType is invalid!");
538fe6060f1SDimitry Andric   }
539fe6060f1SDimitry Andric   if (IsPointer)
540fe6060f1SDimitry Andric     Str += " *";
541fe6060f1SDimitry Andric }
542fe6060f1SDimitry Andric 
543fe6060f1SDimitry Andric void RVVType::initShortStr() {
544fe6060f1SDimitry Andric   switch (ScalarType) {
545fe6060f1SDimitry Andric   case ScalarTypeKind::Boolean:
546fe6060f1SDimitry Andric     assert(isVector());
547fe6060f1SDimitry Andric     ShortStr = "b" + utostr(64 / Scale.getValue());
548fe6060f1SDimitry Andric     return;
549fe6060f1SDimitry Andric   case ScalarTypeKind::Float:
550fe6060f1SDimitry Andric     ShortStr = "f" + utostr(ElementBitwidth);
551fe6060f1SDimitry Andric     break;
552fe6060f1SDimitry Andric   case ScalarTypeKind::SignedInteger:
553fe6060f1SDimitry Andric     ShortStr = "i" + utostr(ElementBitwidth);
554fe6060f1SDimitry Andric     break;
555fe6060f1SDimitry Andric   case ScalarTypeKind::UnsignedInteger:
556fe6060f1SDimitry Andric     ShortStr = "u" + utostr(ElementBitwidth);
557fe6060f1SDimitry Andric     break;
558fe6060f1SDimitry Andric   default:
559fe6060f1SDimitry Andric     PrintFatalError("Unhandled case!");
560fe6060f1SDimitry Andric   }
561fe6060f1SDimitry Andric   if (isVector())
562fe6060f1SDimitry Andric     ShortStr += LMUL.str();
563fe6060f1SDimitry Andric }
564fe6060f1SDimitry Andric 
565fe6060f1SDimitry Andric void RVVType::applyBasicType() {
566fe6060f1SDimitry Andric   switch (BT) {
567fe6060f1SDimitry Andric   case 'c':
568fe6060f1SDimitry Andric     ElementBitwidth = 8;
569fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::SignedInteger;
570fe6060f1SDimitry Andric     break;
571fe6060f1SDimitry Andric   case 's':
572fe6060f1SDimitry Andric     ElementBitwidth = 16;
573fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::SignedInteger;
574fe6060f1SDimitry Andric     break;
575fe6060f1SDimitry Andric   case 'i':
576fe6060f1SDimitry Andric     ElementBitwidth = 32;
577fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::SignedInteger;
578fe6060f1SDimitry Andric     break;
579fe6060f1SDimitry Andric   case 'l':
580fe6060f1SDimitry Andric     ElementBitwidth = 64;
581fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::SignedInteger;
582fe6060f1SDimitry Andric     break;
583fe6060f1SDimitry Andric   case 'x':
584fe6060f1SDimitry Andric     ElementBitwidth = 16;
585fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::Float;
586fe6060f1SDimitry Andric     break;
587fe6060f1SDimitry Andric   case 'f':
588fe6060f1SDimitry Andric     ElementBitwidth = 32;
589fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::Float;
590fe6060f1SDimitry Andric     break;
591fe6060f1SDimitry Andric   case 'd':
592fe6060f1SDimitry Andric     ElementBitwidth = 64;
593fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::Float;
594fe6060f1SDimitry Andric     break;
595fe6060f1SDimitry Andric   default:
596fe6060f1SDimitry Andric     PrintFatalError("Unhandled type code!");
597fe6060f1SDimitry Andric   }
598fe6060f1SDimitry Andric   assert(ElementBitwidth != 0 && "Bad element bitwidth!");
599fe6060f1SDimitry Andric }
600fe6060f1SDimitry Andric 
601fe6060f1SDimitry Andric void RVVType::applyModifier(StringRef Transformer) {
602fe6060f1SDimitry Andric   if (Transformer.empty())
603fe6060f1SDimitry Andric     return;
604fe6060f1SDimitry Andric   // Handle primitive type transformer
605fe6060f1SDimitry Andric   auto PType = Transformer.back();
606fe6060f1SDimitry Andric   switch (PType) {
607fe6060f1SDimitry Andric   case 'e':
608fe6060f1SDimitry Andric     Scale = 0;
609fe6060f1SDimitry Andric     break;
610fe6060f1SDimitry Andric   case 'v':
611fe6060f1SDimitry Andric     Scale = LMUL.getScale(ElementBitwidth);
612fe6060f1SDimitry Andric     break;
613fe6060f1SDimitry Andric   case 'w':
614fe6060f1SDimitry Andric     ElementBitwidth *= 2;
615fe6060f1SDimitry Andric     LMUL *= 2;
616fe6060f1SDimitry Andric     Scale = LMUL.getScale(ElementBitwidth);
617fe6060f1SDimitry Andric     break;
618fe6060f1SDimitry Andric   case 'q':
619fe6060f1SDimitry Andric     ElementBitwidth *= 4;
620fe6060f1SDimitry Andric     LMUL *= 4;
621fe6060f1SDimitry Andric     Scale = LMUL.getScale(ElementBitwidth);
622fe6060f1SDimitry Andric     break;
623fe6060f1SDimitry Andric   case 'o':
624fe6060f1SDimitry Andric     ElementBitwidth *= 8;
625fe6060f1SDimitry Andric     LMUL *= 8;
626fe6060f1SDimitry Andric     Scale = LMUL.getScale(ElementBitwidth);
627fe6060f1SDimitry Andric     break;
628fe6060f1SDimitry Andric   case 'm':
629fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::Boolean;
630fe6060f1SDimitry Andric     Scale = LMUL.getScale(ElementBitwidth);
631fe6060f1SDimitry Andric     ElementBitwidth = 1;
632fe6060f1SDimitry Andric     break;
633fe6060f1SDimitry Andric   case '0':
634fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::Void;
635fe6060f1SDimitry Andric     break;
636fe6060f1SDimitry Andric   case 'z':
637fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::Size_t;
638fe6060f1SDimitry Andric     break;
639fe6060f1SDimitry Andric   case 't':
640fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::Ptrdiff_t;
641fe6060f1SDimitry Andric     break;
642fe6060f1SDimitry Andric   case 'u':
643fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::UnsignedLong;
644fe6060f1SDimitry Andric     break;
645fe6060f1SDimitry Andric   case 'l':
646fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::SignedLong;
647fe6060f1SDimitry Andric     break;
648fe6060f1SDimitry Andric   default:
649fe6060f1SDimitry Andric     PrintFatalError("Illegal primitive type transformers!");
650fe6060f1SDimitry Andric   }
651fe6060f1SDimitry Andric   Transformer = Transformer.drop_back();
652fe6060f1SDimitry Andric 
653fe6060f1SDimitry Andric   // Extract and compute complex type transformer. It can only appear one time.
654fe6060f1SDimitry Andric   if (Transformer.startswith("(")) {
655fe6060f1SDimitry Andric     size_t Idx = Transformer.find(')');
656fe6060f1SDimitry Andric     assert(Idx != StringRef::npos);
657fe6060f1SDimitry Andric     StringRef ComplexType = Transformer.slice(1, Idx);
658fe6060f1SDimitry Andric     Transformer = Transformer.drop_front(Idx + 1);
659*349cc55cSDimitry Andric     assert(!Transformer.contains('(') &&
660fe6060f1SDimitry Andric            "Only allow one complex type transformer");
661fe6060f1SDimitry Andric 
662fe6060f1SDimitry Andric     auto UpdateAndCheckComplexProto = [&]() {
663fe6060f1SDimitry Andric       Scale = LMUL.getScale(ElementBitwidth);
664fe6060f1SDimitry Andric       const StringRef VectorPrototypes("vwqom");
665fe6060f1SDimitry Andric       if (!VectorPrototypes.contains(PType))
666fe6060f1SDimitry Andric         PrintFatalError("Complex type transformer only supports vector type!");
667fe6060f1SDimitry Andric       if (Transformer.find_first_of("PCKWS") != StringRef::npos)
668fe6060f1SDimitry Andric         PrintFatalError(
669fe6060f1SDimitry Andric             "Illegal type transformer for Complex type transformer");
670fe6060f1SDimitry Andric     };
671fe6060f1SDimitry Andric     auto ComputeFixedLog2LMUL =
672fe6060f1SDimitry Andric         [&](StringRef Value,
673fe6060f1SDimitry Andric             std::function<bool(const int32_t &, const int32_t &)> Compare) {
674fe6060f1SDimitry Andric           int32_t Log2LMUL;
675fe6060f1SDimitry Andric           Value.getAsInteger(10, Log2LMUL);
676fe6060f1SDimitry Andric           if (!Compare(Log2LMUL, LMUL.Log2LMUL)) {
677fe6060f1SDimitry Andric             ScalarType = Invalid;
678fe6060f1SDimitry Andric             return false;
679fe6060f1SDimitry Andric           }
680fe6060f1SDimitry Andric           // Update new LMUL
681fe6060f1SDimitry Andric           LMUL = LMULType(Log2LMUL);
682fe6060f1SDimitry Andric           UpdateAndCheckComplexProto();
683fe6060f1SDimitry Andric           return true;
684fe6060f1SDimitry Andric         };
685fe6060f1SDimitry Andric     auto ComplexTT = ComplexType.split(":");
686fe6060f1SDimitry Andric     if (ComplexTT.first == "Log2EEW") {
687fe6060f1SDimitry Andric       uint32_t Log2EEW;
688fe6060f1SDimitry Andric       ComplexTT.second.getAsInteger(10, Log2EEW);
689fe6060f1SDimitry Andric       // update new elmul = (eew/sew) * lmul
690fe6060f1SDimitry Andric       LMUL.MulLog2LMUL(Log2EEW - Log2_32(ElementBitwidth));
691fe6060f1SDimitry Andric       // update new eew
692fe6060f1SDimitry Andric       ElementBitwidth = 1 << Log2EEW;
693fe6060f1SDimitry Andric       ScalarType = ScalarTypeKind::SignedInteger;
694fe6060f1SDimitry Andric       UpdateAndCheckComplexProto();
695fe6060f1SDimitry Andric     } else if (ComplexTT.first == "FixedSEW") {
696fe6060f1SDimitry Andric       uint32_t NewSEW;
697fe6060f1SDimitry Andric       ComplexTT.second.getAsInteger(10, NewSEW);
698fe6060f1SDimitry Andric       // Set invalid type if src and dst SEW are same.
699fe6060f1SDimitry Andric       if (ElementBitwidth == NewSEW) {
700fe6060f1SDimitry Andric         ScalarType = Invalid;
701fe6060f1SDimitry Andric         return;
702fe6060f1SDimitry Andric       }
703fe6060f1SDimitry Andric       // Update new SEW
704fe6060f1SDimitry Andric       ElementBitwidth = NewSEW;
705fe6060f1SDimitry Andric       UpdateAndCheckComplexProto();
706fe6060f1SDimitry Andric     } else if (ComplexTT.first == "LFixedLog2LMUL") {
707fe6060f1SDimitry Andric       // New LMUL should be larger than old
708fe6060f1SDimitry Andric       if (!ComputeFixedLog2LMUL(ComplexTT.second, std::greater<int32_t>()))
709fe6060f1SDimitry Andric         return;
710fe6060f1SDimitry Andric     } else if (ComplexTT.first == "SFixedLog2LMUL") {
711fe6060f1SDimitry Andric       // New LMUL should be smaller than old
712fe6060f1SDimitry Andric       if (!ComputeFixedLog2LMUL(ComplexTT.second, std::less<int32_t>()))
713fe6060f1SDimitry Andric         return;
714fe6060f1SDimitry Andric     } else {
715fe6060f1SDimitry Andric       PrintFatalError("Illegal complex type transformers!");
716fe6060f1SDimitry Andric     }
717fe6060f1SDimitry Andric   }
718fe6060f1SDimitry Andric 
719fe6060f1SDimitry Andric   // Compute the remain type transformers
720fe6060f1SDimitry Andric   for (char I : Transformer) {
721fe6060f1SDimitry Andric     switch (I) {
722fe6060f1SDimitry Andric     case 'P':
723fe6060f1SDimitry Andric       if (IsConstant)
724fe6060f1SDimitry Andric         PrintFatalError("'P' transformer cannot be used after 'C'");
725fe6060f1SDimitry Andric       if (IsPointer)
726fe6060f1SDimitry Andric         PrintFatalError("'P' transformer cannot be used twice");
727fe6060f1SDimitry Andric       IsPointer = true;
728fe6060f1SDimitry Andric       break;
729fe6060f1SDimitry Andric     case 'C':
730fe6060f1SDimitry Andric       if (IsConstant)
731fe6060f1SDimitry Andric         PrintFatalError("'C' transformer cannot be used twice");
732fe6060f1SDimitry Andric       IsConstant = true;
733fe6060f1SDimitry Andric       break;
734fe6060f1SDimitry Andric     case 'K':
735fe6060f1SDimitry Andric       IsImmediate = true;
736fe6060f1SDimitry Andric       break;
737fe6060f1SDimitry Andric     case 'U':
738fe6060f1SDimitry Andric       ScalarType = ScalarTypeKind::UnsignedInteger;
739fe6060f1SDimitry Andric       break;
740fe6060f1SDimitry Andric     case 'I':
741fe6060f1SDimitry Andric       ScalarType = ScalarTypeKind::SignedInteger;
742fe6060f1SDimitry Andric       break;
743fe6060f1SDimitry Andric     case 'F':
744fe6060f1SDimitry Andric       ScalarType = ScalarTypeKind::Float;
745fe6060f1SDimitry Andric       break;
746fe6060f1SDimitry Andric     case 'S':
747fe6060f1SDimitry Andric       LMUL = LMULType(0);
748fe6060f1SDimitry Andric       // Update ElementBitwidth need to update Scale too.
749fe6060f1SDimitry Andric       Scale = LMUL.getScale(ElementBitwidth);
750fe6060f1SDimitry Andric       break;
751fe6060f1SDimitry Andric     default:
752fe6060f1SDimitry Andric       PrintFatalError("Illegal non-primitive type transformer!");
753fe6060f1SDimitry Andric     }
754fe6060f1SDimitry Andric   }
755fe6060f1SDimitry Andric }
756fe6060f1SDimitry Andric 
757fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
758fe6060f1SDimitry Andric // RVVIntrinsic implementation
759fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
760fe6060f1SDimitry Andric RVVIntrinsic::RVVIntrinsic(StringRef NewName, StringRef Suffix,
761fe6060f1SDimitry Andric                            StringRef NewMangledName, StringRef MangledSuffix,
762*349cc55cSDimitry Andric                            StringRef IRName, bool IsMask,
763*349cc55cSDimitry Andric                            bool HasMaskedOffOperand, bool HasVL, bool HasPolicy,
764fe6060f1SDimitry Andric                            bool HasNoMaskedOverloaded, bool HasAutoDef,
765fe6060f1SDimitry Andric                            StringRef ManualCodegen, const RVVTypes &OutInTypes,
766fe6060f1SDimitry Andric                            const std::vector<int64_t> &NewIntrinsicTypes,
767fe6060f1SDimitry Andric                            StringRef RequiredExtension, unsigned NF)
768*349cc55cSDimitry Andric     : IRName(IRName), IsMask(IsMask), HasVL(HasVL), HasPolicy(HasPolicy),
769fe6060f1SDimitry Andric       HasNoMaskedOverloaded(HasNoMaskedOverloaded), HasAutoDef(HasAutoDef),
770fe6060f1SDimitry Andric       ManualCodegen(ManualCodegen.str()), NF(NF) {
771fe6060f1SDimitry Andric 
772*349cc55cSDimitry Andric   // Init BuiltinName, Name and MangledName
773*349cc55cSDimitry Andric   BuiltinName = NewName.str();
774*349cc55cSDimitry Andric   Name = BuiltinName;
775fe6060f1SDimitry Andric   if (NewMangledName.empty())
776fe6060f1SDimitry Andric     MangledName = NewName.split("_").first.str();
777fe6060f1SDimitry Andric   else
778fe6060f1SDimitry Andric     MangledName = NewMangledName.str();
779fe6060f1SDimitry Andric   if (!Suffix.empty())
780fe6060f1SDimitry Andric     Name += "_" + Suffix.str();
781fe6060f1SDimitry Andric   if (!MangledSuffix.empty())
782fe6060f1SDimitry Andric     MangledName += "_" + MangledSuffix.str();
783fe6060f1SDimitry Andric   if (IsMask) {
784*349cc55cSDimitry Andric     BuiltinName += "_m";
785fe6060f1SDimitry Andric     Name += "_m";
786fe6060f1SDimitry Andric   }
787*349cc55cSDimitry Andric 
788fe6060f1SDimitry Andric   // Init RISC-V extensions
789fe6060f1SDimitry Andric   for (const auto &T : OutInTypes) {
790fe6060f1SDimitry Andric     if (T->isFloatVector(16) || T->isFloat(16))
791fe6060f1SDimitry Andric       RISCVExtensions |= RISCVExtension::Zfh;
792fe6060f1SDimitry Andric     else if (T->isFloatVector(32) || T->isFloat(32))
793fe6060f1SDimitry Andric       RISCVExtensions |= RISCVExtension::F;
794fe6060f1SDimitry Andric     else if (T->isFloatVector(64) || T->isFloat(64))
795fe6060f1SDimitry Andric       RISCVExtensions |= RISCVExtension::D;
796fe6060f1SDimitry Andric   }
797fe6060f1SDimitry Andric   if (RequiredExtension == "Zvlsseg")
798fe6060f1SDimitry Andric     RISCVExtensions |= RISCVExtension::Zvlsseg;
799fe6060f1SDimitry Andric 
800fe6060f1SDimitry Andric   // Init OutputType and InputTypes
801fe6060f1SDimitry Andric   OutputType = OutInTypes[0];
802fe6060f1SDimitry Andric   InputTypes.assign(OutInTypes.begin() + 1, OutInTypes.end());
803fe6060f1SDimitry Andric 
804fe6060f1SDimitry Andric   // IntrinsicTypes is nonmasked version index. Need to update it
805fe6060f1SDimitry Andric   // if there is maskedoff operand (It is always in first operand).
806fe6060f1SDimitry Andric   IntrinsicTypes = NewIntrinsicTypes;
807fe6060f1SDimitry Andric   if (IsMask && HasMaskedOffOperand) {
808fe6060f1SDimitry Andric     for (auto &I : IntrinsicTypes) {
809fe6060f1SDimitry Andric       if (I >= 0)
810fe6060f1SDimitry Andric         I += NF;
811fe6060f1SDimitry Andric     }
812fe6060f1SDimitry Andric   }
813fe6060f1SDimitry Andric }
814fe6060f1SDimitry Andric 
815fe6060f1SDimitry Andric std::string RVVIntrinsic::getBuiltinTypeStr() const {
816fe6060f1SDimitry Andric   std::string S;
817fe6060f1SDimitry Andric   S += OutputType->getBuiltinStr();
818fe6060f1SDimitry Andric   for (const auto &T : InputTypes) {
819fe6060f1SDimitry Andric     S += T->getBuiltinStr();
820fe6060f1SDimitry Andric   }
821fe6060f1SDimitry Andric   return S;
822fe6060f1SDimitry Andric }
823fe6060f1SDimitry Andric 
824fe6060f1SDimitry Andric void RVVIntrinsic::emitCodeGenSwitchBody(raw_ostream &OS) const {
825fe6060f1SDimitry Andric   if (!getIRName().empty())
826fe6060f1SDimitry Andric     OS << "  ID = Intrinsic::riscv_" + getIRName() + ";\n";
827fe6060f1SDimitry Andric   if (NF >= 2)
828fe6060f1SDimitry Andric     OS << "  NF = " + utostr(getNF()) + ";\n";
829fe6060f1SDimitry Andric   if (hasManualCodegen()) {
830fe6060f1SDimitry Andric     OS << ManualCodegen;
831fe6060f1SDimitry Andric     OS << "break;\n";
832fe6060f1SDimitry Andric     return;
833fe6060f1SDimitry Andric   }
834fe6060f1SDimitry Andric 
835fe6060f1SDimitry Andric   if (isMask()) {
836fe6060f1SDimitry Andric     if (hasVL()) {
837fe6060f1SDimitry Andric       OS << "  std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n";
838*349cc55cSDimitry Andric       if (hasPolicy())
839*349cc55cSDimitry Andric         OS << "  Ops.push_back(ConstantInt::get(Ops.back()->getType(),"
840*349cc55cSDimitry Andric                                " TAIL_UNDISTURBED));\n";
841fe6060f1SDimitry Andric     } else {
842fe6060f1SDimitry Andric       OS << "  std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n";
843fe6060f1SDimitry Andric     }
844fe6060f1SDimitry Andric   }
845fe6060f1SDimitry Andric 
846fe6060f1SDimitry Andric   OS << "  IntrinsicTypes = {";
847fe6060f1SDimitry Andric   ListSeparator LS;
848fe6060f1SDimitry Andric   for (const auto &Idx : IntrinsicTypes) {
849fe6060f1SDimitry Andric     if (Idx == -1)
850fe6060f1SDimitry Andric       OS << LS << "ResultType";
851fe6060f1SDimitry Andric     else
852fe6060f1SDimitry Andric       OS << LS << "Ops[" << Idx << "]->getType()";
853fe6060f1SDimitry Andric   }
854fe6060f1SDimitry Andric 
855fe6060f1SDimitry Andric   // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is
856fe6060f1SDimitry Andric   // always last operand.
857fe6060f1SDimitry Andric   if (hasVL())
858fe6060f1SDimitry Andric     OS << ", Ops.back()->getType()";
859fe6060f1SDimitry Andric   OS << "};\n";
860fe6060f1SDimitry Andric   OS << "  break;\n";
861fe6060f1SDimitry Andric }
862fe6060f1SDimitry Andric 
863*349cc55cSDimitry Andric void RVVIntrinsic::emitIntrinsicFuncDef(raw_ostream &OS) const {
864*349cc55cSDimitry Andric   OS << "__attribute__((__clang_builtin_alias__(";
865*349cc55cSDimitry Andric   OS << "__builtin_rvv_" << getBuiltinName() << ")))\n";
866*349cc55cSDimitry Andric   OS << OutputType->getTypeStr() << " " << getName() << "(";
867*349cc55cSDimitry Andric   // Emit function arguments
868fe6060f1SDimitry Andric   if (!InputTypes.empty()) {
869fe6060f1SDimitry Andric     ListSeparator LS;
870*349cc55cSDimitry Andric     for (unsigned i = 0; i < InputTypes.size(); ++i)
871*349cc55cSDimitry Andric       OS << LS << InputTypes[i]->getTypeStr();
872fe6060f1SDimitry Andric   }
873*349cc55cSDimitry Andric   OS << ");\n";
874fe6060f1SDimitry Andric }
875fe6060f1SDimitry Andric 
876fe6060f1SDimitry Andric void RVVIntrinsic::emitMangledFuncDef(raw_ostream &OS) const {
877*349cc55cSDimitry Andric   OS << "__attribute__((__clang_builtin_alias__(";
878*349cc55cSDimitry Andric   OS << "__builtin_rvv_" << getBuiltinName() << ")))\n";
879fe6060f1SDimitry Andric   OS << OutputType->getTypeStr() << " " << getMangledName() << "(";
880fe6060f1SDimitry Andric   // Emit function arguments
881fe6060f1SDimitry Andric   if (!InputTypes.empty()) {
882fe6060f1SDimitry Andric     ListSeparator LS;
883fe6060f1SDimitry Andric     for (unsigned i = 0; i < InputTypes.size(); ++i)
884*349cc55cSDimitry Andric       OS << LS << InputTypes[i]->getTypeStr();
885fe6060f1SDimitry Andric   }
886*349cc55cSDimitry Andric   OS << ");\n";
887fe6060f1SDimitry Andric }
888fe6060f1SDimitry Andric 
889fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
890fe6060f1SDimitry Andric // RVVEmitter implementation
891fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
892fe6060f1SDimitry Andric void RVVEmitter::createHeader(raw_ostream &OS) {
893fe6060f1SDimitry Andric 
894fe6060f1SDimitry Andric   OS << "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics "
895fe6060f1SDimitry Andric         "-------------------===\n"
896fe6060f1SDimitry Andric         " *\n"
897fe6060f1SDimitry Andric         " *\n"
898fe6060f1SDimitry Andric         " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
899fe6060f1SDimitry Andric         "Exceptions.\n"
900fe6060f1SDimitry Andric         " * See https://llvm.org/LICENSE.txt for license information.\n"
901fe6060f1SDimitry Andric         " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
902fe6060f1SDimitry Andric         " *\n"
903fe6060f1SDimitry Andric         " *===-----------------------------------------------------------------"
904fe6060f1SDimitry Andric         "------===\n"
905fe6060f1SDimitry Andric         " */\n\n";
906fe6060f1SDimitry Andric 
907fe6060f1SDimitry Andric   OS << "#ifndef __RISCV_VECTOR_H\n";
908fe6060f1SDimitry Andric   OS << "#define __RISCV_VECTOR_H\n\n";
909fe6060f1SDimitry Andric 
910fe6060f1SDimitry Andric   OS << "#include <stdint.h>\n";
911fe6060f1SDimitry Andric   OS << "#include <stddef.h>\n\n";
912fe6060f1SDimitry Andric 
913fe6060f1SDimitry Andric   OS << "#ifndef __riscv_vector\n";
914fe6060f1SDimitry Andric   OS << "#error \"Vector intrinsics require the vector extension.\"\n";
915fe6060f1SDimitry Andric   OS << "#endif\n\n";
916fe6060f1SDimitry Andric 
917fe6060f1SDimitry Andric   OS << "#ifdef __cplusplus\n";
918fe6060f1SDimitry Andric   OS << "extern \"C\" {\n";
919fe6060f1SDimitry Andric   OS << "#endif\n\n";
920fe6060f1SDimitry Andric 
921*349cc55cSDimitry Andric   createRVVHeaders(OS);
922*349cc55cSDimitry Andric 
923fe6060f1SDimitry Andric   std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
924fe6060f1SDimitry Andric   createRVVIntrinsics(Defs);
925fe6060f1SDimitry Andric 
926fe6060f1SDimitry Andric   // Print header code
927fe6060f1SDimitry Andric   if (!HeaderCode.empty()) {
928fe6060f1SDimitry Andric     OS << HeaderCode;
929fe6060f1SDimitry Andric   }
930fe6060f1SDimitry Andric 
931fe6060f1SDimitry Andric   auto printType = [&](auto T) {
932fe6060f1SDimitry Andric     OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr()
933fe6060f1SDimitry Andric        << ";\n";
934fe6060f1SDimitry Andric   };
935fe6060f1SDimitry Andric 
936fe6060f1SDimitry Andric   constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3};
937fe6060f1SDimitry Andric   // Print RVV boolean types.
938fe6060f1SDimitry Andric   for (int Log2LMUL : Log2LMULs) {
939fe6060f1SDimitry Andric     auto T = computeType('c', Log2LMUL, "m");
940fe6060f1SDimitry Andric     if (T.hasValue())
941fe6060f1SDimitry Andric       printType(T.getValue());
942fe6060f1SDimitry Andric   }
943fe6060f1SDimitry Andric   // Print RVV int/float types.
944fe6060f1SDimitry Andric   for (char I : StringRef("csil")) {
945fe6060f1SDimitry Andric     for (int Log2LMUL : Log2LMULs) {
946fe6060f1SDimitry Andric       auto T = computeType(I, Log2LMUL, "v");
947fe6060f1SDimitry Andric       if (T.hasValue()) {
948fe6060f1SDimitry Andric         printType(T.getValue());
949fe6060f1SDimitry Andric         auto UT = computeType(I, Log2LMUL, "Uv");
950fe6060f1SDimitry Andric         printType(UT.getValue());
951fe6060f1SDimitry Andric       }
952fe6060f1SDimitry Andric     }
953fe6060f1SDimitry Andric   }
954fe6060f1SDimitry Andric   OS << "#if defined(__riscv_zfh)\n";
955fe6060f1SDimitry Andric   for (int Log2LMUL : Log2LMULs) {
956fe6060f1SDimitry Andric     auto T = computeType('x', Log2LMUL, "v");
957fe6060f1SDimitry Andric     if (T.hasValue())
958fe6060f1SDimitry Andric       printType(T.getValue());
959fe6060f1SDimitry Andric   }
960fe6060f1SDimitry Andric   OS << "#endif\n";
961fe6060f1SDimitry Andric 
962fe6060f1SDimitry Andric   OS << "#if defined(__riscv_f)\n";
963fe6060f1SDimitry Andric   for (int Log2LMUL : Log2LMULs) {
964fe6060f1SDimitry Andric     auto T = computeType('f', Log2LMUL, "v");
965fe6060f1SDimitry Andric     if (T.hasValue())
966fe6060f1SDimitry Andric       printType(T.getValue());
967fe6060f1SDimitry Andric   }
968fe6060f1SDimitry Andric   OS << "#endif\n";
969fe6060f1SDimitry Andric 
970fe6060f1SDimitry Andric   OS << "#if defined(__riscv_d)\n";
971fe6060f1SDimitry Andric   for (int Log2LMUL : Log2LMULs) {
972fe6060f1SDimitry Andric     auto T = computeType('d', Log2LMUL, "v");
973fe6060f1SDimitry Andric     if (T.hasValue())
974fe6060f1SDimitry Andric       printType(T.getValue());
975fe6060f1SDimitry Andric   }
976fe6060f1SDimitry Andric   OS << "#endif\n\n";
977fe6060f1SDimitry Andric 
978fe6060f1SDimitry Andric   // The same extension include in the same arch guard marco.
979*349cc55cSDimitry Andric   llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A,
980fe6060f1SDimitry Andric                              const std::unique_ptr<RVVIntrinsic> &B) {
981fe6060f1SDimitry Andric     return A->getRISCVExtensions() < B->getRISCVExtensions();
982fe6060f1SDimitry Andric   });
983fe6060f1SDimitry Andric 
984*349cc55cSDimitry Andric   OS << "#define __rvv_ai static __inline__\n";
985*349cc55cSDimitry Andric 
986fe6060f1SDimitry Andric   // Print intrinsic functions with macro
987fe6060f1SDimitry Andric   emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) {
988*349cc55cSDimitry Andric     OS << "__rvv_ai ";
989*349cc55cSDimitry Andric     Inst.emitIntrinsicFuncDef(OS);
990fe6060f1SDimitry Andric   });
991fe6060f1SDimitry Andric 
992*349cc55cSDimitry Andric   OS << "#undef __rvv_ai\n\n";
993*349cc55cSDimitry Andric 
994fe6060f1SDimitry Andric   OS << "#define __riscv_v_intrinsic_overloading 1\n";
995fe6060f1SDimitry Andric 
996fe6060f1SDimitry Andric   // Print Overloaded APIs
997*349cc55cSDimitry Andric   OS << "#define __rvv_aio static __inline__ "
998*349cc55cSDimitry Andric         "__attribute__((__overloadable__))\n";
999fe6060f1SDimitry Andric 
1000fe6060f1SDimitry Andric   emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) {
1001fe6060f1SDimitry Andric     if (!Inst.isMask() && !Inst.hasNoMaskedOverloaded())
1002fe6060f1SDimitry Andric       return;
1003*349cc55cSDimitry Andric     OS << "__rvv_aio ";
1004fe6060f1SDimitry Andric     Inst.emitMangledFuncDef(OS);
1005fe6060f1SDimitry Andric   });
1006fe6060f1SDimitry Andric 
1007*349cc55cSDimitry Andric   OS << "#undef __rvv_aio\n";
1008*349cc55cSDimitry Andric 
1009fe6060f1SDimitry Andric   OS << "\n#ifdef __cplusplus\n";
1010fe6060f1SDimitry Andric   OS << "}\n";
1011*349cc55cSDimitry Andric   OS << "#endif // __cplusplus\n";
1012fe6060f1SDimitry Andric   OS << "#endif // __RISCV_VECTOR_H\n";
1013fe6060f1SDimitry Andric }
1014fe6060f1SDimitry Andric 
1015fe6060f1SDimitry Andric void RVVEmitter::createBuiltins(raw_ostream &OS) {
1016fe6060f1SDimitry Andric   std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
1017fe6060f1SDimitry Andric   createRVVIntrinsics(Defs);
1018fe6060f1SDimitry Andric 
1019*349cc55cSDimitry Andric   // Map to keep track of which builtin names have already been emitted.
1020*349cc55cSDimitry Andric   StringMap<RVVIntrinsic *> BuiltinMap;
1021*349cc55cSDimitry Andric 
1022fe6060f1SDimitry Andric   OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n";
1023fe6060f1SDimitry Andric   OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, "
1024fe6060f1SDimitry Andric         "ATTRS, \"experimental-v\")\n";
1025fe6060f1SDimitry Andric   OS << "#endif\n";
1026fe6060f1SDimitry Andric   for (auto &Def : Defs) {
1027*349cc55cSDimitry Andric     auto P =
1028*349cc55cSDimitry Andric         BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get()));
1029*349cc55cSDimitry Andric     if (!P.second) {
1030*349cc55cSDimitry Andric       // Verify that this would have produced the same builtin definition.
1031*349cc55cSDimitry Andric       if (P.first->second->hasAutoDef() != Def->hasAutoDef()) {
1032*349cc55cSDimitry Andric         PrintFatalError("Builtin with same name has different hasAutoDef");
1033*349cc55cSDimitry Andric       } else if (!Def->hasAutoDef() && P.first->second->getBuiltinTypeStr() !=
1034*349cc55cSDimitry Andric                                            Def->getBuiltinTypeStr()) {
1035*349cc55cSDimitry Andric         PrintFatalError("Builtin with same name has different type string");
1036*349cc55cSDimitry Andric       }
1037*349cc55cSDimitry Andric       continue;
1038*349cc55cSDimitry Andric     }
1039*349cc55cSDimitry Andric 
1040*349cc55cSDimitry Andric     OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getBuiltinName() << ",\"";
1041*349cc55cSDimitry Andric     if (!Def->hasAutoDef())
1042*349cc55cSDimitry Andric       OS << Def->getBuiltinTypeStr();
1043*349cc55cSDimitry Andric     OS << "\", \"n\")\n";
1044fe6060f1SDimitry Andric   }
1045fe6060f1SDimitry Andric   OS << "#undef RISCVV_BUILTIN\n";
1046fe6060f1SDimitry Andric }
1047fe6060f1SDimitry Andric 
1048fe6060f1SDimitry Andric void RVVEmitter::createCodeGen(raw_ostream &OS) {
1049fe6060f1SDimitry Andric   std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
1050fe6060f1SDimitry Andric   createRVVIntrinsics(Defs);
1051fe6060f1SDimitry Andric   // IR name could be empty, use the stable sort preserves the relative order.
1052*349cc55cSDimitry Andric   llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A,
1053fe6060f1SDimitry Andric                              const std::unique_ptr<RVVIntrinsic> &B) {
1054fe6060f1SDimitry Andric     return A->getIRName() < B->getIRName();
1055fe6060f1SDimitry Andric   });
1056*349cc55cSDimitry Andric 
1057*349cc55cSDimitry Andric   // Map to keep track of which builtin names have already been emitted.
1058*349cc55cSDimitry Andric   StringMap<RVVIntrinsic *> BuiltinMap;
1059*349cc55cSDimitry Andric 
1060fe6060f1SDimitry Andric   // Print switch body when the ir name or ManualCodegen changes from previous
1061fe6060f1SDimitry Andric   // iteration.
1062fe6060f1SDimitry Andric   RVVIntrinsic *PrevDef = Defs.begin()->get();
1063fe6060f1SDimitry Andric   for (auto &Def : Defs) {
1064fe6060f1SDimitry Andric     StringRef CurIRName = Def->getIRName();
1065fe6060f1SDimitry Andric     if (CurIRName != PrevDef->getIRName() ||
1066fe6060f1SDimitry Andric         (Def->getManualCodegen() != PrevDef->getManualCodegen())) {
1067fe6060f1SDimitry Andric       PrevDef->emitCodeGenSwitchBody(OS);
1068fe6060f1SDimitry Andric     }
1069fe6060f1SDimitry Andric     PrevDef = Def.get();
1070*349cc55cSDimitry Andric 
1071*349cc55cSDimitry Andric     auto P =
1072*349cc55cSDimitry Andric         BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get()));
1073*349cc55cSDimitry Andric     if (P.second) {
1074*349cc55cSDimitry Andric       OS << "case RISCVVector::BI__builtin_rvv_" << Def->getBuiltinName()
1075*349cc55cSDimitry Andric          << ":\n";
1076*349cc55cSDimitry Andric       continue;
1077*349cc55cSDimitry Andric     }
1078*349cc55cSDimitry Andric 
1079*349cc55cSDimitry Andric     if (P.first->second->getIRName() != Def->getIRName())
1080*349cc55cSDimitry Andric       PrintFatalError("Builtin with same name has different IRName");
1081*349cc55cSDimitry Andric     else if (P.first->second->getManualCodegen() != Def->getManualCodegen())
1082*349cc55cSDimitry Andric       PrintFatalError("Builtin with same name has different ManualCodegen");
1083*349cc55cSDimitry Andric     else if (P.first->second->getNF() != Def->getNF())
1084*349cc55cSDimitry Andric       PrintFatalError("Builtin with same name has different NF");
1085*349cc55cSDimitry Andric     else if (P.first->second->isMask() != Def->isMask())
1086*349cc55cSDimitry Andric       PrintFatalError("Builtin with same name has different isMask");
1087*349cc55cSDimitry Andric     else if (P.first->second->hasVL() != Def->hasVL())
1088*349cc55cSDimitry Andric       PrintFatalError("Builtin with same name has different HasPolicy");
1089*349cc55cSDimitry Andric     else if (P.first->second->hasPolicy() != Def->hasPolicy())
1090*349cc55cSDimitry Andric       PrintFatalError("Builtin with same name has different HasPolicy");
1091*349cc55cSDimitry Andric     else if (P.first->second->getIntrinsicTypes() != Def->getIntrinsicTypes())
1092*349cc55cSDimitry Andric       PrintFatalError("Builtin with same name has different IntrinsicTypes");
1093fe6060f1SDimitry Andric   }
1094fe6060f1SDimitry Andric   Defs.back()->emitCodeGenSwitchBody(OS);
1095fe6060f1SDimitry Andric   OS << "\n";
1096fe6060f1SDimitry Andric }
1097fe6060f1SDimitry Andric 
1098fe6060f1SDimitry Andric void RVVEmitter::parsePrototypes(StringRef Prototypes,
1099fe6060f1SDimitry Andric                                  std::function<void(StringRef)> Handler) {
1100fe6060f1SDimitry Andric   const StringRef Primaries("evwqom0ztul");
1101fe6060f1SDimitry Andric   while (!Prototypes.empty()) {
1102fe6060f1SDimitry Andric     size_t Idx = 0;
1103fe6060f1SDimitry Andric     // Skip over complex prototype because it could contain primitive type
1104fe6060f1SDimitry Andric     // character.
1105fe6060f1SDimitry Andric     if (Prototypes[0] == '(')
1106fe6060f1SDimitry Andric       Idx = Prototypes.find_first_of(')');
1107fe6060f1SDimitry Andric     Idx = Prototypes.find_first_of(Primaries, Idx);
1108fe6060f1SDimitry Andric     assert(Idx != StringRef::npos);
1109fe6060f1SDimitry Andric     Handler(Prototypes.slice(0, Idx + 1));
1110fe6060f1SDimitry Andric     Prototypes = Prototypes.drop_front(Idx + 1);
1111fe6060f1SDimitry Andric   }
1112fe6060f1SDimitry Andric }
1113fe6060f1SDimitry Andric 
1114fe6060f1SDimitry Andric std::string RVVEmitter::getSuffixStr(char Type, int Log2LMUL,
1115fe6060f1SDimitry Andric                                      StringRef Prototypes) {
1116fe6060f1SDimitry Andric   SmallVector<std::string> SuffixStrs;
1117fe6060f1SDimitry Andric   parsePrototypes(Prototypes, [&](StringRef Proto) {
1118fe6060f1SDimitry Andric     auto T = computeType(Type, Log2LMUL, Proto);
1119fe6060f1SDimitry Andric     SuffixStrs.push_back(T.getValue()->getShortStr());
1120fe6060f1SDimitry Andric   });
1121fe6060f1SDimitry Andric   return join(SuffixStrs, "_");
1122fe6060f1SDimitry Andric }
1123fe6060f1SDimitry Andric 
1124fe6060f1SDimitry Andric void RVVEmitter::createRVVIntrinsics(
1125fe6060f1SDimitry Andric     std::vector<std::unique_ptr<RVVIntrinsic>> &Out) {
1126fe6060f1SDimitry Andric   std::vector<Record *> RV = Records.getAllDerivedDefinitions("RVVBuiltin");
1127fe6060f1SDimitry Andric   for (auto *R : RV) {
1128fe6060f1SDimitry Andric     StringRef Name = R->getValueAsString("Name");
1129fe6060f1SDimitry Andric     StringRef SuffixProto = R->getValueAsString("Suffix");
1130fe6060f1SDimitry Andric     StringRef MangledName = R->getValueAsString("MangledName");
1131fe6060f1SDimitry Andric     StringRef MangledSuffixProto = R->getValueAsString("MangledSuffix");
1132fe6060f1SDimitry Andric     StringRef Prototypes = R->getValueAsString("Prototype");
1133fe6060f1SDimitry Andric     StringRef TypeRange = R->getValueAsString("TypeRange");
1134fe6060f1SDimitry Andric     bool HasMask = R->getValueAsBit("HasMask");
1135fe6060f1SDimitry Andric     bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand");
1136fe6060f1SDimitry Andric     bool HasVL = R->getValueAsBit("HasVL");
1137*349cc55cSDimitry Andric     bool HasPolicy = R->getValueAsBit("HasPolicy");
1138fe6060f1SDimitry Andric     bool HasNoMaskedOverloaded = R->getValueAsBit("HasNoMaskedOverloaded");
1139fe6060f1SDimitry Andric     std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL");
1140fe6060f1SDimitry Andric     StringRef ManualCodegen = R->getValueAsString("ManualCodegen");
1141fe6060f1SDimitry Andric     StringRef ManualCodegenMask = R->getValueAsString("ManualCodegenMask");
1142fe6060f1SDimitry Andric     std::vector<int64_t> IntrinsicTypes =
1143fe6060f1SDimitry Andric         R->getValueAsListOfInts("IntrinsicTypes");
1144fe6060f1SDimitry Andric     StringRef RequiredExtension = R->getValueAsString("RequiredExtension");
1145fe6060f1SDimitry Andric     StringRef IRName = R->getValueAsString("IRName");
1146fe6060f1SDimitry Andric     StringRef IRNameMask = R->getValueAsString("IRNameMask");
1147fe6060f1SDimitry Andric     unsigned NF = R->getValueAsInt("NF");
1148fe6060f1SDimitry Andric 
1149fe6060f1SDimitry Andric     StringRef HeaderCodeStr = R->getValueAsString("HeaderCode");
1150fe6060f1SDimitry Andric     bool HasAutoDef = HeaderCodeStr.empty();
1151fe6060f1SDimitry Andric     if (!HeaderCodeStr.empty()) {
1152fe6060f1SDimitry Andric       HeaderCode += HeaderCodeStr.str();
1153fe6060f1SDimitry Andric     }
1154fe6060f1SDimitry Andric     // Parse prototype and create a list of primitive type with transformers
1155fe6060f1SDimitry Andric     // (operand) in ProtoSeq. ProtoSeq[0] is output operand.
1156fe6060f1SDimitry Andric     SmallVector<std::string> ProtoSeq;
1157fe6060f1SDimitry Andric     parsePrototypes(Prototypes, [&ProtoSeq](StringRef Proto) {
1158fe6060f1SDimitry Andric       ProtoSeq.push_back(Proto.str());
1159fe6060f1SDimitry Andric     });
1160fe6060f1SDimitry Andric 
1161fe6060f1SDimitry Andric     // Compute Builtin types
1162fe6060f1SDimitry Andric     SmallVector<std::string> ProtoMaskSeq = ProtoSeq;
1163fe6060f1SDimitry Andric     if (HasMask) {
1164fe6060f1SDimitry Andric       // If HasMaskedOffOperand, insert result type as first input operand.
1165fe6060f1SDimitry Andric       if (HasMaskedOffOperand) {
1166fe6060f1SDimitry Andric         if (NF == 1) {
1167fe6060f1SDimitry Andric           ProtoMaskSeq.insert(ProtoMaskSeq.begin() + 1, ProtoSeq[0]);
1168fe6060f1SDimitry Andric         } else {
1169fe6060f1SDimitry Andric           // Convert
1170fe6060f1SDimitry Andric           // (void, op0 address, op1 address, ...)
1171fe6060f1SDimitry Andric           // to
1172fe6060f1SDimitry Andric           // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
1173fe6060f1SDimitry Andric           for (unsigned I = 0; I < NF; ++I)
1174fe6060f1SDimitry Andric             ProtoMaskSeq.insert(
1175fe6060f1SDimitry Andric                 ProtoMaskSeq.begin() + NF + 1,
1176fe6060f1SDimitry Andric                 ProtoSeq[1].substr(1)); // Use substr(1) to skip '*'
1177fe6060f1SDimitry Andric         }
1178fe6060f1SDimitry Andric       }
1179fe6060f1SDimitry Andric       if (HasMaskedOffOperand && NF > 1) {
1180fe6060f1SDimitry Andric         // Convert
1181fe6060f1SDimitry Andric         // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
1182fe6060f1SDimitry Andric         // to
1183fe6060f1SDimitry Andric         // (void, op0 address, op1 address, ..., mask, maskedoff0, maskedoff1,
1184fe6060f1SDimitry Andric         // ...)
1185fe6060f1SDimitry Andric         ProtoMaskSeq.insert(ProtoMaskSeq.begin() + NF + 1, "m");
1186fe6060f1SDimitry Andric       } else {
1187fe6060f1SDimitry Andric         // If HasMask, insert 'm' as first input operand.
1188fe6060f1SDimitry Andric         ProtoMaskSeq.insert(ProtoMaskSeq.begin() + 1, "m");
1189fe6060f1SDimitry Andric       }
1190fe6060f1SDimitry Andric     }
1191fe6060f1SDimitry Andric     // If HasVL, append 'z' to last operand
1192fe6060f1SDimitry Andric     if (HasVL) {
1193fe6060f1SDimitry Andric       ProtoSeq.push_back("z");
1194fe6060f1SDimitry Andric       ProtoMaskSeq.push_back("z");
1195fe6060f1SDimitry Andric     }
1196fe6060f1SDimitry Andric 
1197fe6060f1SDimitry Andric     // Create Intrinsics for each type and LMUL.
1198fe6060f1SDimitry Andric     for (char I : TypeRange) {
1199fe6060f1SDimitry Andric       for (int Log2LMUL : Log2LMULList) {
1200fe6060f1SDimitry Andric         Optional<RVVTypes> Types = computeTypes(I, Log2LMUL, NF, ProtoSeq);
1201fe6060f1SDimitry Andric         // Ignored to create new intrinsic if there are any illegal types.
1202fe6060f1SDimitry Andric         if (!Types.hasValue())
1203fe6060f1SDimitry Andric           continue;
1204fe6060f1SDimitry Andric 
1205fe6060f1SDimitry Andric         auto SuffixStr = getSuffixStr(I, Log2LMUL, SuffixProto);
1206fe6060f1SDimitry Andric         auto MangledSuffixStr = getSuffixStr(I, Log2LMUL, MangledSuffixProto);
1207fe6060f1SDimitry Andric         // Create a non-mask intrinsic
1208fe6060f1SDimitry Andric         Out.push_back(std::make_unique<RVVIntrinsic>(
1209fe6060f1SDimitry Andric             Name, SuffixStr, MangledName, MangledSuffixStr, IRName,
1210*349cc55cSDimitry Andric             /*IsMask=*/false, /*HasMaskedOffOperand=*/false, HasVL, HasPolicy,
1211*349cc55cSDimitry Andric             HasNoMaskedOverloaded, HasAutoDef, ManualCodegen, Types.getValue(),
1212*349cc55cSDimitry Andric             IntrinsicTypes, RequiredExtension, NF));
1213fe6060f1SDimitry Andric         if (HasMask) {
1214fe6060f1SDimitry Andric           // Create a mask intrinsic
1215fe6060f1SDimitry Andric           Optional<RVVTypes> MaskTypes =
1216fe6060f1SDimitry Andric               computeTypes(I, Log2LMUL, NF, ProtoMaskSeq);
1217fe6060f1SDimitry Andric           Out.push_back(std::make_unique<RVVIntrinsic>(
1218fe6060f1SDimitry Andric               Name, SuffixStr, MangledName, MangledSuffixStr, IRNameMask,
1219*349cc55cSDimitry Andric               /*IsMask=*/true, HasMaskedOffOperand, HasVL, HasPolicy,
1220fe6060f1SDimitry Andric               HasNoMaskedOverloaded, HasAutoDef, ManualCodegenMask,
1221fe6060f1SDimitry Andric               MaskTypes.getValue(), IntrinsicTypes, RequiredExtension, NF));
1222fe6060f1SDimitry Andric         }
1223fe6060f1SDimitry Andric       } // end for Log2LMULList
1224fe6060f1SDimitry Andric     }   // end for TypeRange
1225fe6060f1SDimitry Andric   }
1226fe6060f1SDimitry Andric }
1227fe6060f1SDimitry Andric 
1228*349cc55cSDimitry Andric void RVVEmitter::createRVVHeaders(raw_ostream &OS) {
1229*349cc55cSDimitry Andric   std::vector<Record *> RVVHeaders =
1230*349cc55cSDimitry Andric       Records.getAllDerivedDefinitions("RVVHeader");
1231*349cc55cSDimitry Andric   for (auto *R : RVVHeaders) {
1232*349cc55cSDimitry Andric     StringRef HeaderCodeStr = R->getValueAsString("HeaderCode");
1233*349cc55cSDimitry Andric     OS << HeaderCodeStr.str();
1234*349cc55cSDimitry Andric   }
1235*349cc55cSDimitry Andric }
1236*349cc55cSDimitry Andric 
1237fe6060f1SDimitry Andric Optional<RVVTypes>
1238fe6060f1SDimitry Andric RVVEmitter::computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
1239fe6060f1SDimitry Andric                          ArrayRef<std::string> PrototypeSeq) {
1240fe6060f1SDimitry Andric   // LMUL x NF must be less than or equal to 8.
1241fe6060f1SDimitry Andric   if ((Log2LMUL >= 1) && (1 << Log2LMUL) * NF > 8)
1242fe6060f1SDimitry Andric     return llvm::None;
1243fe6060f1SDimitry Andric 
1244fe6060f1SDimitry Andric   RVVTypes Types;
1245fe6060f1SDimitry Andric   for (const std::string &Proto : PrototypeSeq) {
1246fe6060f1SDimitry Andric     auto T = computeType(BT, Log2LMUL, Proto);
1247fe6060f1SDimitry Andric     if (!T.hasValue())
1248fe6060f1SDimitry Andric       return llvm::None;
1249fe6060f1SDimitry Andric     // Record legal type index
1250fe6060f1SDimitry Andric     Types.push_back(T.getValue());
1251fe6060f1SDimitry Andric   }
1252fe6060f1SDimitry Andric   return Types;
1253fe6060f1SDimitry Andric }
1254fe6060f1SDimitry Andric 
1255fe6060f1SDimitry Andric Optional<RVVTypePtr> RVVEmitter::computeType(BasicType BT, int Log2LMUL,
1256fe6060f1SDimitry Andric                                              StringRef Proto) {
1257fe6060f1SDimitry Andric   std::string Idx = Twine(Twine(BT) + Twine(Log2LMUL) + Proto).str();
1258fe6060f1SDimitry Andric   // Search first
1259fe6060f1SDimitry Andric   auto It = LegalTypes.find(Idx);
1260fe6060f1SDimitry Andric   if (It != LegalTypes.end())
1261fe6060f1SDimitry Andric     return &(It->second);
1262fe6060f1SDimitry Andric   if (IllegalTypes.count(Idx))
1263fe6060f1SDimitry Andric     return llvm::None;
1264fe6060f1SDimitry Andric   // Compute type and record the result.
1265fe6060f1SDimitry Andric   RVVType T(BT, Log2LMUL, Proto);
1266fe6060f1SDimitry Andric   if (T.isValid()) {
1267fe6060f1SDimitry Andric     // Record legal type index and value.
1268fe6060f1SDimitry Andric     LegalTypes.insert({Idx, T});
1269fe6060f1SDimitry Andric     return &(LegalTypes[Idx]);
1270fe6060f1SDimitry Andric   }
1271fe6060f1SDimitry Andric   // Record illegal type index.
1272fe6060f1SDimitry Andric   IllegalTypes.insert(Idx);
1273fe6060f1SDimitry Andric   return llvm::None;
1274fe6060f1SDimitry Andric }
1275fe6060f1SDimitry Andric 
1276fe6060f1SDimitry Andric void RVVEmitter::emitArchMacroAndBody(
1277fe6060f1SDimitry Andric     std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &OS,
1278fe6060f1SDimitry Andric     std::function<void(raw_ostream &, const RVVIntrinsic &)> PrintBody) {
1279fe6060f1SDimitry Andric   uint8_t PrevExt = (*Defs.begin())->getRISCVExtensions();
1280fe6060f1SDimitry Andric   bool NeedEndif = emitExtDefStr(PrevExt, OS);
1281fe6060f1SDimitry Andric   for (auto &Def : Defs) {
1282fe6060f1SDimitry Andric     uint8_t CurExt = Def->getRISCVExtensions();
1283fe6060f1SDimitry Andric     if (CurExt != PrevExt) {
1284fe6060f1SDimitry Andric       if (NeedEndif)
1285fe6060f1SDimitry Andric         OS << "#endif\n\n";
1286fe6060f1SDimitry Andric       NeedEndif = emitExtDefStr(CurExt, OS);
1287fe6060f1SDimitry Andric       PrevExt = CurExt;
1288fe6060f1SDimitry Andric     }
1289fe6060f1SDimitry Andric     if (Def->hasAutoDef())
1290fe6060f1SDimitry Andric       PrintBody(OS, *Def);
1291fe6060f1SDimitry Andric   }
1292fe6060f1SDimitry Andric   if (NeedEndif)
1293fe6060f1SDimitry Andric     OS << "#endif\n\n";
1294fe6060f1SDimitry Andric }
1295fe6060f1SDimitry Andric 
1296fe6060f1SDimitry Andric bool RVVEmitter::emitExtDefStr(uint8_t Extents, raw_ostream &OS) {
1297fe6060f1SDimitry Andric   if (Extents == RISCVExtension::Basic)
1298fe6060f1SDimitry Andric     return false;
1299fe6060f1SDimitry Andric   OS << "#if ";
1300fe6060f1SDimitry Andric   ListSeparator LS(" && ");
1301fe6060f1SDimitry Andric   if (Extents & RISCVExtension::F)
1302fe6060f1SDimitry Andric     OS << LS << "defined(__riscv_f)";
1303fe6060f1SDimitry Andric   if (Extents & RISCVExtension::D)
1304fe6060f1SDimitry Andric     OS << LS << "defined(__riscv_d)";
1305fe6060f1SDimitry Andric   if (Extents & RISCVExtension::Zfh)
1306fe6060f1SDimitry Andric     OS << LS << "defined(__riscv_zfh)";
1307fe6060f1SDimitry Andric   if (Extents & RISCVExtension::Zvlsseg)
1308fe6060f1SDimitry Andric     OS << LS << "defined(__riscv_zvlsseg)";
1309fe6060f1SDimitry Andric   OS << "\n";
1310fe6060f1SDimitry Andric   return true;
1311fe6060f1SDimitry Andric }
1312fe6060f1SDimitry Andric 
1313fe6060f1SDimitry Andric namespace clang {
1314fe6060f1SDimitry Andric void EmitRVVHeader(RecordKeeper &Records, raw_ostream &OS) {
1315fe6060f1SDimitry Andric   RVVEmitter(Records).createHeader(OS);
1316fe6060f1SDimitry Andric }
1317fe6060f1SDimitry Andric 
1318fe6060f1SDimitry Andric void EmitRVVBuiltins(RecordKeeper &Records, raw_ostream &OS) {
1319fe6060f1SDimitry Andric   RVVEmitter(Records).createBuiltins(OS);
1320fe6060f1SDimitry Andric }
1321fe6060f1SDimitry Andric 
1322fe6060f1SDimitry Andric void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
1323fe6060f1SDimitry Andric   RVVEmitter(Records).createCodeGen(OS);
1324fe6060f1SDimitry Andric }
1325fe6060f1SDimitry Andric 
1326fe6060f1SDimitry Andric } // End namespace clang
1327